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/860] 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/860] 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/860] 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/860] 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/860] 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 a60d73b4a8244d9874b42c510e86532d7e424e69 Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Sun, 5 May 2024 10:30:44 -0400 Subject: [PATCH 006/860] fix plugin template for monorepo plugins Signed-off-by: aramissennyeydd --- .changeset/shy-hounds-battle.md | 5 +++++ packages/cli/templates/default-backend-plugin/README.md.hbs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/shy-hounds-battle.md diff --git a/.changeset/shy-hounds-battle.md b/.changeset/shy-hounds-battle.md new file mode 100644 index 0000000000..11d66e0d94 --- /dev/null +++ b/.changeset/shy-hounds-battle.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix a bug in the backend plugin template that was creating an incorrect link. diff --git a/packages/cli/templates/default-backend-plugin/README.md.hbs b/packages/cli/templates/default-backend-plugin/README.md.hbs index e95c626167..48a4ddb848 100644 --- a/packages/cli/templates/default-backend-plugin/README.md.hbs +++ b/packages/cli/templates/default-backend-plugin/README.md.hbs @@ -11,4 +11,4 @@ start` in the root directory, and then navigating to [/{{pluginVar}}/health](htt 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. +It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. From 4ba352071a29733aa8c88ee58e1292547868b8bc Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Sun, 5 May 2024 10:42:01 -0400 Subject: [PATCH 007/860] fix express types as well Signed-off-by: aramissennyeydd --- packages/cli/templates/default-backend-plugin/package.json.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/templates/default-backend-plugin/package.json.hbs b/packages/cli/templates/default-backend-plugin/package.json.hbs index 6b7aa915aa..289bb1ff69 100644 --- a/packages/cli/templates/default-backend-plugin/package.json.hbs +++ b/packages/cli/templates/default-backend-plugin/package.json.hbs @@ -32,7 +32,6 @@ "@backstage/backend-defaults": "{{versionQuery '@backstage/backend-defaults'}}", "@backstage/backend-plugin-api": "{{versionQuery '@backstage/backend-plugin-api'}}", "@backstage/config": "{{versionQuery '@backstage/config'}}", - "@types/express": "{{versionQuery '@types/express' '4.17.6'}}", "express": "{{versionQuery 'express' '4.17.1'}}", "express-promise-router": "{{versionQuery 'express-promise-router' '4.1.0'}}", "winston": "{{versionQuery 'winston' '3.2.1'}}", @@ -43,6 +42,7 @@ "@backstage/cli": "{{versionQuery '@backstage/cli'}}", "@backstage/plugin-auth-backend": "{{versionQuery '@backstage/plugin-auth-backend'}}", "@backstage/plugin-auth-backend-module-guest-provider": "{{versionQuery '@backstage/plugin-auth-backend-module-guest-provider'}}", + "@types/express": "{{versionQuery '@types/express' '4.17.6'}}", "@types/supertest": "{{versionQuery '@types/supertest' '2.0.12'}}", "supertest": "{{versionQuery 'supertest' '6.2.4'}}", "msw": "{{versionQuery 'msw' '1.0.0'}}" From 31c99f53a890aa083834bd9a198979c02373ac1d Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Sun, 5 May 2024 15:13:43 -0400 Subject: [PATCH 008/860] adjust release notes Signed-off-by: aramissennyeydd --- .changeset/shy-hounds-battle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/shy-hounds-battle.md b/.changeset/shy-hounds-battle.md index 11d66e0d94..bfcf46c076 100644 --- a/.changeset/shy-hounds-battle.md +++ b/.changeset/shy-hounds-battle.md @@ -2,4 +2,4 @@ '@backstage/cli': patch --- -Fix a bug in the backend plugin template that was creating an incorrect link. +Fix a few minor issues with the backend template that were causing failing linting checks in the main repo. 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 009/860] 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 010/860] 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 011/860] 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 012/860] 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 0e797b37f4a5fa74d00bd0065aad73dfe140e55c Mon Sep 17 00:00:00 2001 From: Brian Phillips <28457+brianphillips@users.noreply.github.com> Date: Wed, 29 May 2024 10:04:09 -0500 Subject: [PATCH 013/860] Add ability to specify a different relationship name for MembersListCard The default relationship remains `memberOf` but could be overridden to specify (for instance) `leaderOf` if you wanted to have multiple MembersListCard components on a `Group` page (one for "Members" and another for "Leaders") Signed-off-by: Brian Phillips <28457+brianphillips@users.noreply.github.com> --- .../MembersList/MembersListCard.test.tsx | 30 +++++++++++++++++++ .../Group/MembersList/MembersListCard.tsx | 4 ++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index 793ffe274b..539b0bd892 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -99,6 +99,7 @@ describe('MemberTab Test', () => { ] as Entity[], }), }; + const getEntitiesSpy = jest.spyOn(catalogApi, 'getEntities'); it('Display Profile Card', async () => { await renderInTestApp( @@ -115,6 +116,12 @@ describe('MemberTab Test', () => { }, }, ); + expect(getEntitiesSpy).toHaveBeenCalledWith({ + filter: { + kind: 'User', + 'relations.memberOf': ['group:default/team-d'], + }, + }); expect(screen.getByAltText('Tara MacGovern')).toHaveAttribute( 'src', @@ -149,6 +156,29 @@ describe('MemberTab Test', () => { expect(screen.getByText('Testers (1)')).toBeInTheDocument(); }); + it('Can query a different relationship', async () => { + await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, + }, + }, + ); + + expect(getEntitiesSpy).toHaveBeenCalledWith({ + filter: { + kind: 'User', + 'relations.leaderOf': ['group:default/team-d'], + }, + }); + }); + describe('Aggregate members toggle', () => { it('Does not show the aggregate members toggle if the showAggregateMembersToggle prop is undefined', async () => { await renderInTestApp( diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index 418a83f5b2..b21ae20c23 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -138,12 +138,14 @@ export const MembersListCard = (props: { memberDisplayTitle?: string; pageSize?: number; showAggregateMembersToggle?: boolean; + relationship?: string; relationsType?: EntityRelationAggregation; }) => { const { memberDisplayTitle = 'Members', pageSize = 50, showAggregateMembersToggle, + relationship = 'memberOf', relationsType = 'direct', } = props; const classes = useListStyles(); @@ -187,7 +189,7 @@ export const MembersListCard = (props: { const membersList = await catalogApi.getEntities({ filter: { kind: 'User', - 'relations.memberof': [ + [`relations.${relationship}`]: [ stringifyEntityRef({ kind: 'group', namespace: groupNamespace.toLocaleLowerCase('en-US'), From c307ef471a3d9868395213d4b69eb3c444b4039e Mon Sep 17 00:00:00 2001 From: Brian Phillips <28457+brianphillips@users.noreply.github.com> Date: Wed, 29 May 2024 10:29:23 -0500 Subject: [PATCH 014/860] add changeset Signed-off-by: Brian Phillips <28457+brianphillips@users.noreply.github.com> --- .changeset/little-games-fail.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/little-games-fail.md diff --git a/.changeset/little-games-fail.md b/.changeset/little-games-fail.md new file mode 100644 index 0000000000..dc5d2f7795 --- /dev/null +++ b/.changeset/little-games-fail.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Added relationship option to EntityMembersListCard component From 2644eeccb955fcf0b6e26f9df1c6b6f3e6d88afc Mon Sep 17 00:00:00 2001 From: Brian Phillips <28457+brianphillips@users.noreply.github.com> Date: Wed, 29 May 2024 13:40:23 -0500 Subject: [PATCH 015/860] Add API report Signed-off-by: Brian Phillips <28457+brianphillips@users.noreply.github.com> --- plugins/org/api-report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/org/api-report.md b/plugins/org/api-report.md index 1960ce839b..fe641e5a8b 100644 --- a/plugins/org/api-report.md +++ b/plugins/org/api-report.md @@ -23,6 +23,7 @@ export const EntityMembersListCard: (props: { memberDisplayTitle?: string | undefined; pageSize?: number | undefined; showAggregateMembersToggle?: boolean | undefined; + relationship?: string | undefined; relationsType?: EntityRelationAggregation | undefined; }) => JSX_2.Element; @@ -55,6 +56,7 @@ export const MembersListCard: (props: { memberDisplayTitle?: string; pageSize?: number; showAggregateMembersToggle?: boolean; + relationship?: string; relationsType?: EntityRelationAggregation; }) => React_2.JSX.Element; From 05ad87ed3aff16d87aa65a62972b0bc529457770 Mon Sep 17 00:00:00 2001 From: Brian Phillips <28457+brianphillips@users.noreply.github.com> Date: Wed, 29 May 2024 14:37:35 -0500 Subject: [PATCH 016/860] fix case mismatch in relationship name Signed-off-by: Brian Phillips <28457+brianphillips@users.noreply.github.com> --- .../Group/MembersList/MembersListCard.test.tsx | 4 ++-- .../Group/MembersList/MembersListCard.tsx | 5 +++-- plugins/org/src/helpers/helpers.ts | 18 +++++++++++------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index 539b0bd892..3a129348c7 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -119,7 +119,7 @@ describe('MemberTab Test', () => { expect(getEntitiesSpy).toHaveBeenCalledWith({ filter: { kind: 'User', - 'relations.memberOf': ['group:default/team-d'], + 'relations.memberof': ['group:default/team-d'], }, }); @@ -174,7 +174,7 @@ describe('MemberTab Test', () => { expect(getEntitiesSpy).toHaveBeenCalledWith({ filter: { kind: 'User', - 'relations.leaderOf': ['group:default/team-d'], + 'relations.leaderof': ['group:default/team-d'], }, }); }); diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index b21ae20c23..d1e74200fd 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -145,7 +145,7 @@ export const MembersListCard = (props: { memberDisplayTitle = 'Members', pageSize = 50, showAggregateMembersToggle, - relationship = 'memberOf', + relationship = 'memberof', relationsType = 'direct', } = props; const classes = useListStyles(); @@ -179,6 +179,7 @@ export const MembersListCard = (props: { return await getAllDesendantMembersForGroupEntity( groupEntity, catalogApi, + relationship, ); }, [catalogApi, groupEntity, showAggregateMembers]); const { @@ -189,7 +190,7 @@ export const MembersListCard = (props: { const membersList = await catalogApi.getEntities({ filter: { kind: 'User', - [`relations.${relationship}`]: [ + [`relations.${relationship.toLocaleLowerCase('en-US')}`]: [ stringifyEntityRef({ kind: 'group', namespace: groupNamespace.toLocaleLowerCase('en-US'), diff --git a/plugins/org/src/helpers/helpers.ts b/plugins/org/src/helpers/helpers.ts index 7da4ee32d8..465f89afa1 100644 --- a/plugins/org/src/helpers/helpers.ts +++ b/plugins/org/src/helpers/helpers.ts @@ -31,6 +31,7 @@ import { export const getMembersFromGroups = async ( groups: CompoundEntityRef[], catalogApi: CatalogApi, + relationship = 'memberof', ) => { const membersList = groups.length === 0 @@ -38,13 +39,14 @@ export const getMembersFromGroups = async ( : await catalogApi.getEntities({ filter: { kind: 'User', - 'relations.memberof': groups.map(group => - stringifyEntityRef({ - kind: 'group', - namespace: group.namespace.toLocaleLowerCase('en-US'), - name: group.name.toLocaleLowerCase('en-US'), - }), - ), + [`relations.${relationship.toLocaleLowerCase('en-US')}`]: + groups.map(group => + stringifyEntityRef({ + kind: 'group', + namespace: group.namespace.toLocaleLowerCase('en-US'), + name: group.name.toLocaleLowerCase('en-US'), + }), + ), }, }); @@ -99,10 +101,12 @@ export const getDescendantGroupsFromGroup = async ( export const getAllDesendantMembersForGroupEntity = async ( groupEntity: GroupEntity, catalogApi: CatalogApi, + relationship = 'memberof', ) => getMembersFromGroups( await getDescendantGroupsFromGroup(groupEntity, catalogApi), catalogApi, + relationship, ); export const removeDuplicateEntitiesFrom = (entityArray: Entity[]) => { From 0410fc9ce605f1495870eaee1715a33e706cf58b Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 30 Apr 2024 11:49:36 +0300 Subject: [PATCH 017/860] feat: allow setting notification read from web/snackbar when opening link from snackbar or web notification, the notification can be automatically set as read like in the notifications page Signed-off-by: Heikki Hellgren --- .changeset/ten-penguins-roll.md | 5 ++++ plugins/notifications/api-report.md | 6 ++++- .../NotificationsSideBarItem.tsx | 23 +++++++++++++++++-- .../src/hooks/useWebNotifications.ts | 23 ++++++++++++++++--- 4 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 .changeset/ten-penguins-roll.md diff --git a/.changeset/ten-penguins-roll.md b/.changeset/ten-penguins-roll.md new file mode 100644 index 0000000000..60e0ae773a --- /dev/null +++ b/.changeset/ten-penguins-roll.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications': patch +--- + +Allow setting notification as read when opening snackbar or web notification link diff --git a/plugins/notifications/api-report.md b/plugins/notifications/api-report.md index 9240bdb1c2..2547204c7b 100644 --- a/plugins/notifications/api-report.md +++ b/plugins/notifications/api-report.md @@ -103,6 +103,7 @@ export const NotificationsSidebarItem: (props?: { titleCounterEnabled?: boolean; snackbarEnabled?: boolean; snackbarAutoHideDuration?: number | null; + markAsReadOnLinkOpen?: boolean; className?: string; icon?: IconComponent; text?: string; @@ -182,7 +183,10 @@ export function useTitleCounter(): { }; // @public (undocumented) -export function useWebNotifications(enabled: boolean): { +export function useWebNotifications( + enabled: boolean, + markAsReadOnLinkOpen: boolean, +): { sendWebNotification: (options: { id: string; title: string; diff --git a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx index 7b55c63747..6e1f7c7d56 100644 --- a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx +++ b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx @@ -84,6 +84,7 @@ export const NotificationsSidebarItem = (props?: { titleCounterEnabled?: boolean; snackbarEnabled?: boolean; snackbarAutoHideDuration?: number | null; + markAsReadOnLinkOpen?: boolean; className?: string; icon?: IconComponent; text?: string; @@ -95,6 +96,7 @@ export const NotificationsSidebarItem = (props?: { titleCounterEnabled = true, snackbarEnabled = true, snackbarAutoHideDuration = 10000, + markAsReadOnLinkOpen = false, icon = NotificationsIcon, text = 'Notifications', ...restProps @@ -103,6 +105,7 @@ export const NotificationsSidebarItem = (props?: { titleCounterEnabled: true, snackbarEnabled: true, snackbarAutoHideDuration: 10000, + markAsReadOnLinkOpen: false, }; const { loading, error, value, retry } = useNotificationsApi(api => @@ -114,7 +117,10 @@ export const NotificationsSidebarItem = (props?: { const notificationsRoute = useRouteRef(rootRouteRef); // TODO: Do we want to add long polling in case signals are not available const { lastSignal } = useSignal('notifications'); - const { sendWebNotification } = useWebNotifications(webNotificationsEnabled); + const { sendWebNotification } = useWebNotifications( + webNotificationsEnabled, + markAsReadOnLinkOpen, + ); const [refresh, setRefresh] = React.useState(false); const { setNotificationCount } = useTitleCounter(); @@ -126,6 +132,19 @@ export const NotificationsSidebarItem = (props?: { component={Link} to={notification.payload.link ?? notificationsRoute()} onClick={() => { + if (markAsReadOnLinkOpen) { + notificationsApi + .updateNotifications({ + ids: [notification.id], + read: true, + }) + .catch(() => { + alertApi.post({ + message: 'Failed to mark notification as read', + severity: 'error', + }); + }); + } closeSnackbar(snackBarId); }} > @@ -156,7 +175,7 @@ export const NotificationsSidebarItem = (props?: { return { action }; }, - [notificationsRoute, notificationsApi, alertApi], + [notificationsRoute, markAsReadOnLinkOpen, notificationsApi, alertApi], ); useEffect(() => { diff --git a/plugins/notifications/src/hooks/useWebNotifications.ts b/plugins/notifications/src/hooks/useWebNotifications.ts index 728d992130..92a0a9b806 100644 --- a/plugins/notifications/src/hooks/useWebNotifications.ts +++ b/plugins/notifications/src/hooks/useWebNotifications.ts @@ -15,14 +15,19 @@ */ import { useCallback, useEffect, useState } from 'react'; import { rootRouteRef } from '../routes'; -import { useRouteRef } from '@backstage/core-plugin-api'; +import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { useNavigate } from 'react-router-dom'; +import { notificationsApiRef } from '../api'; /** @public */ -export function useWebNotifications(enabled: boolean) { +export function useWebNotifications( + enabled: boolean, + markAsReadOnLinkOpen: boolean, +) { const [webNotificationPermission, setWebNotificationPermission] = useState('default'); const notificationsRoute = useRouteRef(rootRouteRef); + const notificationsApi = useApi(notificationsApiRef); const navigate = useNavigate(); useEffect(() => { @@ -57,6 +62,12 @@ export function useWebNotifications(enabled: boolean) { event.preventDefault(); if (options.link) { window.open(options.link, '_blank'); + if (markAsReadOnLinkOpen) { + notificationsApi.updateNotifications({ + ids: [options.id], + read: true, + }); + } } else { navigate(notificationsRoute()); } @@ -65,7 +76,13 @@ export function useWebNotifications(enabled: boolean) { return notification; }, - [webNotificationPermission, navigate, notificationsRoute], + [ + webNotificationPermission, + markAsReadOnLinkOpen, + notificationsApi, + navigate, + notificationsRoute, + ], ); return { sendWebNotification }; From a880e941aaf1382189169b3416df51ec4b2c0b6c Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Thu, 30 May 2024 15:45:38 +0300 Subject: [PATCH 018/860] fix: change notification hooks to internal Signed-off-by: Heikki Hellgren --- plugins/notifications/api-report.md | 18 ------------------ .../notifications/src/hooks/useTitleCounter.ts | 2 +- .../src/hooks/useWebNotifications.ts | 2 +- plugins/notifications/src/index.ts | 2 +- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/plugins/notifications/api-report.md b/plugins/notifications/api-report.md index 2547204c7b..c431664883 100644 --- a/plugins/notifications/api-report.md +++ b/plugins/notifications/api-report.md @@ -177,23 +177,5 @@ export function useNotificationsApi( value: T; }; -// @public (undocumented) -export function useTitleCounter(): { - setNotificationCount: (newCount: number) => void; -}; - -// @public (undocumented) -export function useWebNotifications( - enabled: boolean, - markAsReadOnLinkOpen: boolean, -): { - sendWebNotification: (options: { - id: string; - title: string; - description: string; - link?: string; - }) => Notification | null; -}; - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/notifications/src/hooks/useTitleCounter.ts b/plugins/notifications/src/hooks/useTitleCounter.ts index 0793cd58d6..399bfb84f4 100644 --- a/plugins/notifications/src/hooks/useTitleCounter.ts +++ b/plugins/notifications/src/hooks/useTitleCounter.ts @@ -25,7 +25,7 @@ const throttledSetTitle = throttle((shownTitle: string) => { document.title = shownTitle; }, 100); -/** @public */ +/** @internal */ export function useTitleCounter() { const [title, setTitle] = useState(document.title); const [count, setCount] = useState(0); diff --git a/plugins/notifications/src/hooks/useWebNotifications.ts b/plugins/notifications/src/hooks/useWebNotifications.ts index 92a0a9b806..3fbd3c5496 100644 --- a/plugins/notifications/src/hooks/useWebNotifications.ts +++ b/plugins/notifications/src/hooks/useWebNotifications.ts @@ -19,7 +19,7 @@ import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { useNavigate } from 'react-router-dom'; import { notificationsApiRef } from '../api'; -/** @public */ +/** @internal */ export function useWebNotifications( enabled: boolean, markAsReadOnLinkOpen: boolean, diff --git a/plugins/notifications/src/index.ts b/plugins/notifications/src/index.ts index bb5d76a0cf..25565f1ae1 100644 --- a/plugins/notifications/src/index.ts +++ b/plugins/notifications/src/index.ts @@ -15,5 +15,5 @@ */ export { notificationsPlugin, NotificationsPage } from './plugin'; export * from './api'; -export * from './hooks'; +export { useNotificationsApi } from './hooks'; export * from './components'; From aa2d3e302acff82c078dcc40dd75fe17144fc5ef Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Thu, 30 May 2024 21:14:02 +0300 Subject: [PATCH 019/860] feat: make default functionality to mark notification read when opening link Signed-off-by: Heikki Hellgren --- .changeset/ten-penguins-roll.md | 4 +-- plugins/notifications/api-report.md | 1 - .../NotificationsSideBarItem.tsx | 13 ++++----- .../src/hooks/useWebNotifications.ts | 29 ++++++------------- 4 files changed, 17 insertions(+), 30 deletions(-) diff --git a/.changeset/ten-penguins-roll.md b/.changeset/ten-penguins-roll.md index 60e0ae773a..152bb1524b 100644 --- a/.changeset/ten-penguins-roll.md +++ b/.changeset/ten-penguins-roll.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-notifications': patch +'@backstage/plugin-notifications': minor --- -Allow setting notification as read when opening snackbar or web notification link +By default, set notification as read when opening snackbar or web notification link diff --git a/plugins/notifications/api-report.md b/plugins/notifications/api-report.md index c431664883..5e06ae2616 100644 --- a/plugins/notifications/api-report.md +++ b/plugins/notifications/api-report.md @@ -103,7 +103,6 @@ export const NotificationsSidebarItem: (props?: { titleCounterEnabled?: boolean; snackbarEnabled?: boolean; snackbarAutoHideDuration?: number | null; - markAsReadOnLinkOpen?: boolean; className?: string; icon?: IconComponent; text?: string; diff --git a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx index 6e1f7c7d56..457893b016 100644 --- a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx +++ b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx @@ -84,7 +84,6 @@ export const NotificationsSidebarItem = (props?: { titleCounterEnabled?: boolean; snackbarEnabled?: boolean; snackbarAutoHideDuration?: number | null; - markAsReadOnLinkOpen?: boolean; className?: string; icon?: IconComponent; text?: string; @@ -96,7 +95,6 @@ export const NotificationsSidebarItem = (props?: { titleCounterEnabled = true, snackbarEnabled = true, snackbarAutoHideDuration = 10000, - markAsReadOnLinkOpen = false, icon = NotificationsIcon, text = 'Notifications', ...restProps @@ -105,7 +103,6 @@ export const NotificationsSidebarItem = (props?: { titleCounterEnabled: true, snackbarEnabled: true, snackbarAutoHideDuration: 10000, - markAsReadOnLinkOpen: false, }; const { loading, error, value, retry } = useNotificationsApi(api => @@ -117,9 +114,8 @@ export const NotificationsSidebarItem = (props?: { const notificationsRoute = useRouteRef(rootRouteRef); // TODO: Do we want to add long polling in case signals are not available const { lastSignal } = useSignal('notifications'); - const { sendWebNotification } = useWebNotifications( + const { sendWebNotification, requestUserPermission } = useWebNotifications( webNotificationsEnabled, - markAsReadOnLinkOpen, ); const [refresh, setRefresh] = React.useState(false); const { setNotificationCount } = useTitleCounter(); @@ -132,7 +128,7 @@ export const NotificationsSidebarItem = (props?: { component={Link} to={notification.payload.link ?? notificationsRoute()} onClick={() => { - if (markAsReadOnLinkOpen) { + if (notification.payload.link) { notificationsApi .updateNotifications({ ids: [notification.id], @@ -175,7 +171,7 @@ export const NotificationsSidebarItem = (props?: { return { action }; }, - [notificationsRoute, markAsReadOnLinkOpen, notificationsApi, alertApi], + [notificationsRoute, notificationsApi, alertApi], ); useEffect(() => { @@ -278,6 +274,9 @@ export const NotificationsSidebarItem = (props?: { )} { + requestUserPermission(); + }} hasNotifications={!error && !!unreadCount} text={text} icon={icon} diff --git a/plugins/notifications/src/hooks/useWebNotifications.ts b/plugins/notifications/src/hooks/useWebNotifications.ts index 3fbd3c5496..ec120a614d 100644 --- a/plugins/notifications/src/hooks/useWebNotifications.ts +++ b/plugins/notifications/src/hooks/useWebNotifications.ts @@ -13,24 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useState } from 'react'; import { rootRouteRef } from '../routes'; import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { useNavigate } from 'react-router-dom'; import { notificationsApiRef } from '../api'; /** @internal */ -export function useWebNotifications( - enabled: boolean, - markAsReadOnLinkOpen: boolean, -) { +export function useWebNotifications(enabled: boolean) { const [webNotificationPermission, setWebNotificationPermission] = useState('default'); const notificationsRoute = useRouteRef(rootRouteRef); const notificationsApi = useApi(notificationsApiRef); const navigate = useNavigate(); - useEffect(() => { + const requestUserPermission = useCallback(() => { if ( enabled && 'Notification' in window && @@ -62,12 +59,10 @@ export function useWebNotifications( event.preventDefault(); if (options.link) { window.open(options.link, '_blank'); - if (markAsReadOnLinkOpen) { - notificationsApi.updateNotifications({ - ids: [options.id], - read: true, - }); - } + notificationsApi.updateNotifications({ + ids: [options.id], + read: true, + }); } else { navigate(notificationsRoute()); } @@ -76,14 +71,8 @@ export function useWebNotifications( return notification; }, - [ - webNotificationPermission, - markAsReadOnLinkOpen, - notificationsApi, - navigate, - notificationsRoute, - ], + [webNotificationPermission, notificationsApi, navigate, notificationsRoute], ); - return { sendWebNotification }; + return { sendWebNotification, requestUserPermission }; } From 90a7340efd87f1174018093dc671f07bff02e733 Mon Sep 17 00:00:00 2001 From: Ooi Yee Fei Date: Sat, 1 Jun 2024 15:09:02 +0800 Subject: [PATCH 020/860] 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 d7b8ca5aca95ab3902c9296dfbbe289383d760ab Mon Sep 17 00:00:00 2001 From: Vladimir Kobzev Date: Mon, 3 Jun 2024 10:58:42 +0200 Subject: [PATCH 021/860] Add topic field to NotificationGetOptions, add router query topic param, add topic filter to DatabaseNotificationsStore.ts, add unit test Signed-off-by: Vladimir Kobzev --- .changeset/sour-jokes-sneeze.md | 5 +++++ .../database/DatabaseNotificationsStore.test.ts | 14 ++++++++++++++ .../src/database/DatabaseNotificationsStore.ts | 4 ++++ .../src/database/NotificationsStore.ts | 1 + .../notifications-backend/src/service/router.ts | 5 +++++ 5 files changed, 29 insertions(+) create mode 100644 .changeset/sour-jokes-sneeze.md diff --git a/.changeset/sour-jokes-sneeze.md b/.changeset/sour-jokes-sneeze.md new file mode 100644 index 0000000000..5cafaea595 --- /dev/null +++ b/.changeset/sour-jokes-sneeze.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications-backend': patch +--- + +Added an option to filter notifications by topic diff --git a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts index 6204629821..c6df60c56e 100644 --- a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts +++ b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts @@ -271,6 +271,20 @@ describe.each(databases.eachSupportedId())( expect(notifications.length).toBe(1); expect(notifications.at(0)?.id).toEqual(id2); }); + + it('should filter notifications based on topic', async () => { + await storage.saveNotification(testNotification1); + await storage.saveNotification(testNotification2); + await storage.saveNotification(testNotification3); + + const notifications = await storage.getNotifications({ + user, + topic: 'efgh-topic', + }); + + expect(notifications.length).toBe(1); + expect(notifications.at(0)?.id).toEqual(id1); + }); }); describe('getNotifications filters on severity', () => { diff --git a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts index f4bd25d1ba..3d027128ec 100644 --- a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts +++ b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts @@ -204,6 +204,10 @@ export class DatabaseNotificationsStore implements NotificationsStore { query.whereNull('read'); } // or match both if undefined + if (options.topic) { + query.where('topic', '=', options.topic); + } + if (options.saved) { query.whereNotNull('saved'); } else if (options.saved === false) { diff --git a/plugins/notifications-backend/src/database/NotificationsStore.ts b/plugins/notifications-backend/src/database/NotificationsStore.ts index 901ea1695d..3c57d0ac4a 100644 --- a/plugins/notifications-backend/src/database/NotificationsStore.ts +++ b/plugins/notifications-backend/src/database/NotificationsStore.ts @@ -35,6 +35,7 @@ export type NotificationGetOptions = { limit?: number; search?: string; orderField?: EntityOrder[]; + topic?: string; read?: boolean; saved?: boolean; createdAfter?: Date; diff --git a/plugins/notifications-backend/src/service/router.ts b/plugins/notifications-backend/src/service/router.ts index bb5c9e06ac..3ca3ce46bc 100644 --- a/plugins/notifications-backend/src/service/router.ts +++ b/plugins/notifications-backend/src/service/router.ts @@ -302,6 +302,11 @@ export async function createRouter( opts.read = false; // or keep undefined } + + if (req.query.topic) { + opts.topic = req.query.topic.toString(); + } + if (req.query.saved === 'true') { opts.saved = true; } else if (req.query.saved === 'false') { From 6a4ad4ee45956936ef1185d3c80b116f7a98330d Mon Sep 17 00:00:00 2001 From: Kacper Nowacki Date: Mon, 3 Jun 2024 14:42:55 +0200 Subject: [PATCH 022/860] Fetch default branch for target repository instead of using hardcoded master branch if no targetBranch is provided Signed-off-by: Kacper Nowacki --- .changeset/fair-rockets-leave.md | 6 +++ .../bitbucketServerPullRequest.test.ts | 18 +++++++ .../src/actions/bitbucketServerPullRequest.ts | 47 ++++++++++++++++++- 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 .changeset/fair-rockets-leave.md diff --git a/.changeset/fair-rockets-leave.md b/.changeset/fair-rockets-leave.md new file mode 100644 index 0000000000..41cf28fc9e --- /dev/null +++ b/.changeset/fair-rockets-leave.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch +--- + +Instead of using hardcoded targetBranch we are fetching 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/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts index 9d2dd915f8..61adf0e3c8 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 @@ -103,6 +103,14 @@ describe('publish:bitbucketServer:pull-request', () => { ], start: 0, }; + const responseOfDefaultBranch = { + id: 'refs/heads/main', + displayId: 'main', + type: 'BRANCH', + latestCommit: '1245346tsdfgdf', + latestChangeset: 'wsdfgdh234', + isDefault: true, + }; const responseOfPullRequests = { id: 19, version: 0, @@ -190,6 +198,16 @@ describe('publish:bitbucketServer:pull-request', () => { ); }, ), + rest.get( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos/repo/default-branch', + (_, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseOfDefaultBranch), + ); + }, + ), rest.post( 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos/repo/pull-requests', (_, res, ctx) => { diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts index 8fddffaba4..440e402764 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts @@ -204,6 +204,39 @@ const createBranch = async (opts: { return await response.json(); }; +const getDefaultBranch = async (opts: { + project: string; + repo: string; + authorization: string; + apiBaseUrl: string; +}) => { + const { project, repo, authorization, apiBaseUrl } = opts; + let response: Response; + + const options: RequestInit = { + method: 'GET', + headers: { + Authorization: authorization, + 'Content-Type': 'application/json', + }, + }; + + try { + response = await fetch( + `${apiBaseUrl}/projects/${project}/repos/${repo}/default-branch`, + options, + ); + } catch (error) { + throw error; + } + + const { displayId } = await response.json(); + const defaultBranch = displayId; + if (!defaultBranch) { + throw new Error(`Could not fetch default branch for ${project}/${repo}`); + } + return defaultBranch; +}; /** * Creates a BitbucketServer Pull Request action. * @public @@ -288,7 +321,7 @@ export function createPublishBitbucketServerPullRequestAction(options: { repoUrl, title, description, - targetBranch = 'master', + targetBranch, sourceBranch, gitAuthorName, gitAuthorEmail, @@ -326,10 +359,20 @@ export function createPublishBitbucketServerPullRequestAction(options: { const apiBaseUrl = integrationConfig.config.apiBaseUrl; + let finalTargetBranch = targetBranch; + if (!finalTargetBranch) { + finalTargetBranch = await getDefaultBranch({ + project, + repo, + authorization, + apiBaseUrl, + }); + } + const toRef = await findBranches({ project, repo, - branchName: targetBranch, + branchName: finalTargetBranch!, authorization, apiBaseUrl, }); 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 023/860] 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 024/860] 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 025/860] 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 026/860] 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 027/860] 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 028/860] 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 029/860] 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 030/860] 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 115741c468c40e508b714dff5ef2577248236888 Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Mon, 27 May 2024 23:11:06 +0200 Subject: [PATCH 031/860] Implement group-based user retrieval for Gitlab based on additional configuration key 'restrictUsersToGroup' Signed-off-by: Hghtwr --- .gitignore | 1 + packages/backend/src/index.ts | 2 +- .../src/lib/client.ts | 21 +++++++++++ .../src/lib/types.ts | 8 +++++ .../GitlabOrgDiscoveryEntityProvider.ts | 35 ++++++++++++++----- .../src/providers/config.test.ts | 4 +++ .../src/providers/config.ts | 3 ++ 7 files changed, 64 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 5ba3da3148..6db4bf549c 100644 --- a/.gitignore +++ b/.gitignore @@ -94,6 +94,7 @@ typings/ # dotenv environment variables file .env .env.test +.envrc # parcel-bundler cache (https://parceljs.org/) .cache diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index a4acd19cf2..621d912844 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -21,7 +21,7 @@ const backend = createBackend(); backend.add(import('@backstage/plugin-auth-backend')); backend.add(import('./authModuleGithubProvider')); backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); - +backend.add(import('@backstage/plugin-catalog-backend-module-gitlab-org')); backend.add(import('@backstage/plugin-app-backend/alpha')); backend.add(import('@backstage/plugin-catalog-backend-module-unprocessed')); backend.add( diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index 8f56657f68..54c19bd3cc 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -23,6 +23,7 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import { GitLabDescendantGroupsResponse, GitLabGroup, + GitlabGroupMember, GitLabGroupMembersResponse, GitLabProject, GitLabUser, @@ -114,8 +115,19 @@ export class GitLabClient { return response; } + async listGroupMembers( + groupPath: string, + options?: CommonListOptions, + ): Promise> { + return this.pagedRequest( + `/groups/${encodeURIComponent(groupPath)}/members/all`, + options, + ); + } + async listUsers( options?: UserListOptions, + global?: boolean, ): Promise> { return this.pagedRequest(`/users?`, { ...options, @@ -128,6 +140,14 @@ export class GitLabClient { groupPath: string, options?: CommonListOptions, ): Promise> { + return this.listGroupMembers(groupPath, { + ...options, + show_seat_info: true, + }).then(resp => { + resp.items = resp.items.filter(user => user.is_using_seat); + return resp; + }); + /* return this.pagedRequest( `/groups/${encodeURIComponent(groupPath)}/members/all`, { @@ -138,6 +158,7 @@ export class GitLabClient { resp.items = resp.items.filter(user => user.is_using_seat); return resp; }); +*/ } async listGroups( diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 2857fea162..89d2ceba1b 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -60,6 +60,7 @@ export type GitLabUser = { avatar_url: string; groups?: GitLabGroup[]; group_saml_identity?: GitLabGroupSamlIdentity; + is_using_seat?: boolean; // Only available in responses from the group members endpoint }; /** @@ -149,6 +150,13 @@ export type GitlabProviderConfig = { * Accepts only groups under the provided path (which will be stripped) */ group: string; + + /** + * If true, the provider will only ingest users that are part of the configured group. + * Only valid for self-hosted GitLab instances. + */ + restrictUsersToGroup?: boolean; + /** * ??? */ diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index e10f9ee313..67a5134f25 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -356,7 +356,24 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { let groups; let users; - if (this.gitLabClient.isSelfManaged()) { + // Doesn't matter if we are on SaaS or not, we can either get the users from the defined group or from the root group. + if (this.gitLabClient.isSelfManaged() && this.config.restrictUsersToGroup) { + groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) + .items; + users = paginated( + options => + this.gitLabClient.listGroupMembers(this.config.group, options), + { + page: 1, + per_page: 100, + }, + ); + } + + if ( + this.gitLabClient.isSelfManaged() && + !this.config.restrictUsersToGroup + ) { groups = paginated( options => this.gitLabClient.listGroups(options), { @@ -365,19 +382,19 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { all_available: true, }, ); - users = paginated( options => this.gitLabClient.listUsers(options), - { - page: 1, - per_page: 100, - active: true, - }, + { page: 1, per_page: 100, active: true }, ); - } else { + } + + // For SaaS, the only difference is the root group + if (!this.gitLabClient.isSelfManaged()) { groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) .items; - const rootGroup = this.config.group.split('/')[0]; + const rootGroup = this.config.restrictUsersToGroup + ? this.config.group + : this.config.group.split('/')[0]; users = paginated( options => this.gitLabClient.listSaaSUsers(rootGroup, options), { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts index 09b42e6475..f53121e064 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts @@ -61,6 +61,7 @@ describe('config', () => { allowInherited: false, schedule: undefined, skipForkedRepos: false, + restrictUsersToGroup: false, }), ); }); @@ -99,6 +100,7 @@ describe('config', () => { allowInherited: false, schedule: undefined, skipForkedRepos: false, + restrictUsersToGroup: false, }), ); }); @@ -137,6 +139,7 @@ describe('config', () => { orgEnabled: false, allowInherited: false, schedule: undefined, + restrictUsersToGroup: false, skipForkedRepos: true, }), ); @@ -178,6 +181,7 @@ describe('config', () => { orgEnabled: false, allowInherited: false, skipForkedRepos: false, + restrictUsersToGroup: false, schedule: { frequency: Duration.fromISO('PT30M'), timeout: { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index 8606a525bd..68eba7165a 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -51,6 +51,8 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { const schedule = config.has('schedule') ? readTaskScheduleDefinitionFromConfig(config.getConfig('schedule')) : undefined; + const restrictUsersToGroup = + config.getOptionalBoolean('restrictUsersToGroup') ?? false; return { id, @@ -66,6 +68,7 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { orgEnabled, allowInherited, skipForkedRepos, + restrictUsersToGroup, }; } From 8db30ad8525062a2eff58294cc1d99977d3ade8d Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Mon, 27 May 2024 23:20:40 +0200 Subject: [PATCH 032/860] Create changeset for restrictUserToGroup configuration key Signed-off-by: Hghtwr --- .changeset/fifty-pumpkins-smell.md | 5 +++++ packages/backend/package.json | 1 + yarn.lock | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/fifty-pumpkins-smell.md diff --git a/.changeset/fifty-pumpkins-smell.md b/.changeset/fifty-pumpkins-smell.md new file mode 100644 index 0000000000..0dceaf7f37 --- /dev/null +++ b/.changeset/fifty-pumpkins-smell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab..restrictUsersToGroup`. Setting this to `true` will make Backstage only import users from the group defined in 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/packages/backend/package.json b/packages/backend/package.json index ba22ddae1e..edad16fb7e 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -38,6 +38,7 @@ "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-catalog-backend-module-backstage-openapi": "workspace:^", + "@backstage/plugin-catalog-backend-module-gitlab-org": "workspace:^", "@backstage/plugin-catalog-backend-module-openapi": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^", diff --git a/yarn.lock b/yarn.lock index a67630c6a5..094f162fd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5379,7 +5379,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-backend-module-gitlab-org@workspace:plugins/catalog-backend-module-gitlab-org": +"@backstage/plugin-catalog-backend-module-gitlab-org@workspace:^, @backstage/plugin-catalog-backend-module-gitlab-org@workspace:plugins/catalog-backend-module-gitlab-org": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-backend-module-gitlab-org@workspace:plugins/catalog-backend-module-gitlab-org" dependencies: @@ -26680,6 +26680,7 @@ __metadata: "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" "@backstage/plugin-catalog-backend-module-backstage-openapi": "workspace:^" + "@backstage/plugin-catalog-backend-module-gitlab-org": "workspace:^" "@backstage/plugin-catalog-backend-module-openapi": "workspace:^" "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^" "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^" From 59df0489963568132b733fa55a19dcc02cc01b7b Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Mon, 27 May 2024 23:30:34 +0200 Subject: [PATCH 033/860] Add explaination for Gitlab's restrictUsersToGroup configuration key Signed-off-by: Hghtwr --- docs/integrations/gitlab/org.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/integrations/gitlab/org.md b/docs/integrations/gitlab/org.md index 2cc0dcfb82..61eefd4868 100644 --- a/docs/integrations/gitlab/org.md +++ b/docs/integrations/gitlab/org.md @@ -196,11 +196,24 @@ which contain members will be ingested. ### Users -For self hosted, all `User` entities are ingested from the entire instance. +For self hosted, all `User` entities are ingested from the entire instance by default. For gitlab.com `User` entities for users who have [direct or inherited membership](https://docs.gitlab.com/ee/user/project/members/index.html#membership-types) of the top-level group for the configured group path will be ingested. +In both cases (SaaS & self hosted), you can limit the ingested users to users directly assigned to the group defined in your `app-config.yaml` by setting the configuration key `restrictUsersToGroup: true`. This is especially useful when you have a large userbase that you don't want to import by default. + +```yaml +catalog: + providers: + gitlab: + yourProviderId: + host: gitlab.com ## Could also be self hosted. + orgEnabled: true + group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only groups under the provided path (which will be stripped) + restrictUsersToGroup: true # Backstage will ingest only users directly assigned to org/teams. +``` + ### Limiting `User` and `Group` entity ingestion in the provider Optionally, you can limit the entity types ingested by the provider when using From 5d4045b09dd7f2f041610d92b4d67bd0af1d95b5 Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Mon, 27 May 2024 23:41:18 +0200 Subject: [PATCH 034/860] Remove gitlab-org used during testing, remove unused types and options Signed-off-by: Hghtwr --- packages/backend/src/index.ts | 1 - plugins/catalog-backend-module-gitlab/src/lib/client.ts | 2 -- plugins/catalog-backend-module-gitlab/src/lib/types.ts | 1 - 3 files changed, 4 deletions(-) diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 621d912844..1174b7bf6d 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -21,7 +21,6 @@ const backend = createBackend(); backend.add(import('@backstage/plugin-auth-backend')); backend.add(import('./authModuleGithubProvider')); backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); -backend.add(import('@backstage/plugin-catalog-backend-module-gitlab-org')); backend.add(import('@backstage/plugin-app-backend/alpha')); backend.add(import('@backstage/plugin-catalog-backend-module-unprocessed')); backend.add( diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index 54c19bd3cc..f80f954a8e 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -23,7 +23,6 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import { GitLabDescendantGroupsResponse, GitLabGroup, - GitlabGroupMember, GitLabGroupMembersResponse, GitLabProject, GitLabUser, @@ -127,7 +126,6 @@ export class GitLabClient { async listUsers( options?: UserListOptions, - global?: boolean, ): Promise> { return this.pagedRequest(`/users?`, { ...options, diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 89d2ceba1b..0b9ea6a868 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -153,7 +153,6 @@ export type GitlabProviderConfig = { /** * If true, the provider will only ingest users that are part of the configured group. - * Only valid for self-hosted GitLab instances. */ restrictUsersToGroup?: boolean; From 70500dd306a0129e4174363dd92fb7c4b7a44bd9 Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Mon, 27 May 2024 23:43:16 +0200 Subject: [PATCH 035/860] Remove former implementation of listSaaSUsers() Signed-off-by: Hghtwr --- .../catalog-backend-module-gitlab/src/lib/client.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index f80f954a8e..b5a2b69131 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -145,18 +145,6 @@ export class GitLabClient { resp.items = resp.items.filter(user => user.is_using_seat); return resp; }); - /* - return this.pagedRequest( - `/groups/${encodeURIComponent(groupPath)}/members/all`, - { - ...options, - show_seat_info: true, - }, - ).then(resp => { - resp.items = resp.items.filter(user => user.is_using_seat); - return resp; - }); -*/ } async listGroups( From 8f34253b902ba9ad4a89046ad148135f1a45cbcf Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Tue, 28 May 2024 09:26:59 +0200 Subject: [PATCH 036/860] Satisfy Typecheck for user/groups by restructuring the if clause Signed-off-by: Hghtwr --- .../src/providers/GitlabOrgDiscoveryEntityProvider.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index 67a5134f25..ce545ebe84 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -368,9 +368,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { per_page: 100, }, ); - } - - if ( + } else if ( this.gitLabClient.isSelfManaged() && !this.config.restrictUsersToGroup ) { @@ -387,9 +385,8 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { { page: 1, per_page: 100, active: true }, ); } - // For SaaS, the only difference is the root group - if (!this.gitLabClient.isSelfManaged()) { + else { groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) .items; const rootGroup = this.config.restrictUsersToGroup From f79798be0410e39b50afcd3bd403e6ef35d85dbe Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Tue, 28 May 2024 09:46:45 +0200 Subject: [PATCH 037/860] Update api report for #24889 Signed-off-by: Hghtwr --- plugins/catalog-backend-module-gitlab/api-report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/catalog-backend-module-gitlab/api-report.md b/plugins/catalog-backend-module-gitlab/api-report.md index d7fcd1b94d..2b78c67205 100644 --- a/plugins/catalog-backend-module-gitlab/api-report.md +++ b/plugins/catalog-backend-module-gitlab/api-report.md @@ -98,6 +98,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { export type GitlabProviderConfig = { host: string; group: string; + restrictUsersToGroup?: boolean; id: string; branch?: string; fallbackBranch: string; @@ -122,6 +123,7 @@ export type GitLabUser = { avatar_url: string; groups?: GitLabGroup[]; group_saml_identity?: GitLabGroupSamlIdentity; + is_using_seat?: boolean; }; // @public From 20de0f8cb8d97c148e5d1081fcc2a265c6eb72a5 Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Tue, 28 May 2024 10:10:39 +0200 Subject: [PATCH 038/860] Remove unused dependencies after testing Signed-off-by: Hghtwr --- packages/backend/package.json | 1 - yarn.lock | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index edad16fb7e..ba22ddae1e 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -38,7 +38,6 @@ "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-catalog-backend-module-backstage-openapi": "workspace:^", - "@backstage/plugin-catalog-backend-module-gitlab-org": "workspace:^", "@backstage/plugin-catalog-backend-module-openapi": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^", diff --git a/yarn.lock b/yarn.lock index 094f162fd0..a67630c6a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5379,7 +5379,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-backend-module-gitlab-org@workspace:^, @backstage/plugin-catalog-backend-module-gitlab-org@workspace:plugins/catalog-backend-module-gitlab-org": +"@backstage/plugin-catalog-backend-module-gitlab-org@workspace:plugins/catalog-backend-module-gitlab-org": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-backend-module-gitlab-org@workspace:plugins/catalog-backend-module-gitlab-org" dependencies: @@ -26680,7 +26680,6 @@ __metadata: "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" "@backstage/plugin-catalog-backend-module-backstage-openapi": "workspace:^" - "@backstage/plugin-catalog-backend-module-gitlab-org": "workspace:^" "@backstage/plugin-catalog-backend-module-openapi": "workspace:^" "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^" "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^" From 08b0740812155788f35479be2dda84fdf3c390f8 Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Tue, 28 May 2024 14:07:07 +0200 Subject: [PATCH 039/860] Fix reviewdog documentation issues Signed-off-by: Hghtwr --- .changeset/fifty-pumpkins-smell.md | 2 +- docs/integrations/gitlab/org.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/fifty-pumpkins-smell.md b/.changeset/fifty-pumpkins-smell.md index 0dceaf7f37..95f4fd3fc1 100644 --- a/.changeset/fifty-pumpkins-smell.md +++ b/.changeset/fifty-pumpkins-smell.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend-module-gitlab': patch --- -The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab..restrictUsersToGroup`. Setting this to `true` will make Backstage only import users from the group defined in 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. +The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab..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/docs/integrations/gitlab/org.md b/docs/integrations/gitlab/org.md index 61eefd4868..fbc89cf8ba 100644 --- a/docs/integrations/gitlab/org.md +++ b/docs/integrations/gitlab/org.md @@ -201,7 +201,7 @@ For self hosted, all `User` entities are ingested from the entire instance by de For gitlab.com `User` entities for users who have [direct or inherited membership](https://docs.gitlab.com/ee/user/project/members/index.html#membership-types) of the top-level group for the configured group path will be ingested. -In both cases (SaaS & self hosted), you can limit the ingested users to users directly assigned to the group defined in your `app-config.yaml` by setting the configuration key `restrictUsersToGroup: true`. This is especially useful when you have a large userbase that you don't want to import by default. +In both cases (SaaS & self hosted), you can limit the ingested users to users directly assigned to the group defined in your `app-config.yaml` by setting the configuration key `restrictUsersToGroup: true`. This is especially useful when you have a large user base that you don't want to import by default. ```yaml catalog: From 4e4ef2ba78a8ead2fdf3bd674ac1ef5dcf313eb0 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Wed, 5 Jun 2024 13:33:31 +0300 Subject: [PATCH 040/860] 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 0391e693babafe46b9d25b86862ac6003b1890f6 Mon Sep 17 00:00:00 2001 From: Brian Phillips <28457+brianphillips@users.noreply.github.com> Date: Thu, 6 Jun 2024 06:37:35 -0500 Subject: [PATCH 041/860] use more sensible property for specifying the relationship type In the process, the `relationsType` prop is deprecated and renamed to `relationAggregation`. Signed-off-by: Brian Phillips <28457+brianphillips@users.noreply.github.com> --- .../Group/MembersList/MembersListCard.test.tsx | 6 +++--- .../Cards/Group/MembersList/MembersListCard.tsx | 15 +++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index 3a129348c7..69d6090687 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -160,7 +160,7 @@ describe('MemberTab Test', () => { await renderInTestApp( - + , { @@ -376,7 +376,7 @@ describe('MemberTab Test', () => { @@ -414,7 +414,7 @@ describe('MemberTab Test', () => { - + diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index d1e74200fd..f27b071114 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -138,16 +138,19 @@ export const MembersListCard = (props: { memberDisplayTitle?: string; pageSize?: number; showAggregateMembersToggle?: boolean; - relationship?: string; + relationType?: string; + /** @deprecated Please use `relationAggregation` instead */ relationsType?: EntityRelationAggregation; + relationAggregation?: EntityRelationAggregation; }) => { const { memberDisplayTitle = 'Members', pageSize = 50, showAggregateMembersToggle, - relationship = 'memberof', - relationsType = 'direct', + relationType = 'memberof', } = props; + const relationAggregation = + props.relationAggregation ?? props.relationsType ?? 'direct'; const classes = useListStyles(); const { entity: groupEntity } = useEntity(); @@ -167,7 +170,7 @@ export const MembersListCard = (props: { }; const [showAggregateMembers, setShowAggregateMembers] = useState( - relationsType === 'aggregated', + relationAggregation === 'aggregated', ); const { loading: loadingDescendantMembers, value: descendantMembers } = @@ -179,7 +182,7 @@ export const MembersListCard = (props: { return await getAllDesendantMembersForGroupEntity( groupEntity, catalogApi, - relationship, + relationType, ); }, [catalogApi, groupEntity, showAggregateMembers]); const { @@ -190,7 +193,7 @@ export const MembersListCard = (props: { const membersList = await catalogApi.getEntities({ filter: { kind: 'User', - [`relations.${relationship.toLocaleLowerCase('en-US')}`]: [ + [`relations.${relationType.toLocaleLowerCase('en-US')}`]: [ stringifyEntityRef({ kind: 'group', namespace: groupNamespace.toLocaleLowerCase('en-US'), From 4a99e6463d2c9cb8786bad750b1915b89c2b0c8a Mon Sep 17 00:00:00 2001 From: Brian Phillips <28457+brianphillips@users.noreply.github.com> Date: Thu, 6 Jun 2024 07:05:29 -0500 Subject: [PATCH 042/860] deprecate all instances of the relationsType property in favor of relationAggregation Signed-off-by: Brian Phillips <28457+brianphillips@users.noreply.github.com> --- .changeset/little-games-fail.md | 4 ++- plugins/org/api-report.md | 8 +++-- .../Cards/OwnershipCard/ComponentsGrid.tsx | 12 +++++-- .../OwnershipCard/OwnershipCard.test.tsx | 2 +- .../Cards/OwnershipCard/OwnershipCard.tsx | 31 +++++++++++-------- .../OwnershipCard/useGetEntities.test.ts | 4 +-- .../Cards/OwnershipCard/useGetEntities.ts | 10 +++--- 7 files changed, 45 insertions(+), 26 deletions(-) diff --git a/.changeset/little-games-fail.md b/.changeset/little-games-fail.md index dc5d2f7795..199f983be8 100644 --- a/.changeset/little-games-fail.md +++ b/.changeset/little-games-fail.md @@ -2,4 +2,6 @@ '@backstage/plugin-org': patch --- -Added relationship option to EntityMembersListCard component +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/plugins/org/api-report.md b/plugins/org/api-report.md index fe641e5a8b..884832c111 100644 --- a/plugins/org/api-report.md +++ b/plugins/org/api-report.md @@ -23,8 +23,9 @@ export const EntityMembersListCard: (props: { memberDisplayTitle?: string | undefined; pageSize?: number | undefined; showAggregateMembersToggle?: boolean | undefined; - relationship?: string | undefined; + relationType?: string | undefined; relationsType?: EntityRelationAggregation | undefined; + relationAggregation?: EntityRelationAggregation | undefined; }) => JSX_2.Element; // @public (undocumented) @@ -33,6 +34,7 @@ export const EntityOwnershipCard: (props: { entityFilterKind?: string[] | undefined; hideRelationsToggle?: boolean | undefined; relationsType?: EntityRelationAggregation | undefined; + relationAggregation?: EntityRelationAggregation | undefined; entityLimit?: number | undefined; }) => JSX_2.Element; @@ -56,8 +58,9 @@ export const MembersListCard: (props: { memberDisplayTitle?: string; pageSize?: number; showAggregateMembersToggle?: boolean; - relationship?: string; + relationType?: string; relationsType?: EntityRelationAggregation; + relationAggregation?: EntityRelationAggregation; }) => React_2.JSX.Element; // @public @@ -84,6 +87,7 @@ export const OwnershipCard: (props: { entityFilterKind?: string[]; hideRelationsToggle?: boolean; relationsType?: EntityRelationAggregation; + relationAggregation?: EntityRelationAggregation; entityLimit?: number; }) => React_2.JSX.Element; diff --git a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx index ff16a4ab2d..586e612e94 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx @@ -107,19 +107,27 @@ export const ComponentsGrid = ({ className, entity, relationsType, + relationAggregation, entityFilterKind, entityLimit = 6, }: { className?: string; entity: Entity; - relationsType: EntityRelationAggregation; + /** @deprecated Please use relationAggregation instead */ + relationsType?: EntityRelationAggregation; + relationAggregation?: EntityRelationAggregation; entityFilterKind?: string[]; entityLimit?: number; }) => { const catalogLink = useRouteRef(catalogIndexRouteRef); + if (!relationsType && !relationAggregation) { + throw new Error( + 'The relationAggregation property must be set as an EntityRelationAggregation type.', + ); + } const { componentsWithCounters, loading, error } = useGetEntities( entity, - relationsType, + (relationAggregation ?? relationsType)!, // we can safely use the non-null assertion here because of the run-time check above entityFilterKind, entityLimit, ); diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index f2b949f768..004fb8b964 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -288,7 +288,7 @@ describe('OwnershipCard', () => { const { getByText } = await renderInTestApp( - + , { diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index a5b0b7bb19..fce47845bc 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -67,31 +67,34 @@ export const OwnershipCard = (props: { variant?: InfoCardVariants; entityFilterKind?: string[]; hideRelationsToggle?: boolean; + /** @deprecated Please use relationAggregation instead */ relationsType?: EntityRelationAggregation; + relationAggregation?: EntityRelationAggregation; entityLimit?: number; }) => { const { variant, entityFilterKind, hideRelationsToggle, - relationsType, entityLimit = 6, } = props; + const relationAggregation = props.relationAggregation ?? props.relationsType; const relationsToggle = hideRelationsToggle === undefined ? false : hideRelationsToggle; const classes = useStyles(); const { entity } = useEntity(); - const defaultRelationsType = entity.kind === 'User' ? 'aggregated' : 'direct'; - const [getRelationsType, setRelationsType] = useState( - relationsType ?? defaultRelationsType, + const defaultRelationAggregation = + entity.kind === 'User' ? 'aggregated' : 'direct'; + const [getRelationAggregation, setRelationAggregation] = useState( + relationAggregation ?? defaultRelationAggregation, ); useEffect(() => { - if (!relationsType) { - setRelationsType(defaultRelationsType); + if (!relationAggregation) { + setRelationAggregation(defaultRelationAggregation); } - }, [setRelationsType, defaultRelationsType, relationsType]); + }, [setRelationAggregation, defaultRelationAggregation, relationAggregation]); return ( { - const updatedRelationsType = - getRelationsType === 'direct' ? 'aggregated' : 'direct'; - setRelationsType(updatedRelationsType); + const updatedRelationAggregation = + getRelationAggregation === 'direct' + ? 'aggregated' + : 'direct'; + setRelationAggregation(updatedRelationAggregation); }} name="pin" inputProps={{ 'aria-label': 'Ownership Type Switch' }} @@ -136,7 +141,7 @@ export const OwnershipCard = (props: { className={classes.grid} entity={entity} entityLimit={entityLimit} - relationsType={getRelationsType} + relationAggregation={getRelationAggregation} entityFilterKind={entityFilterKind} /> diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts index eac5a171ba..c6cec557c1 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts @@ -64,7 +64,7 @@ describe('useGetEntities', () => { ]), }); - describe('given aggregated relationsType', () => { + describe('given aggregated relationAggregation', () => { const whenHookIsCalledWith = async (_entity: Entity) => { const { result } = renderHook( ({ entity }) => useGetEntities(entity, 'aggregated'), @@ -205,7 +205,7 @@ describe('useGetEntities', () => { }); }); - describe('given direct relationsType', () => { + describe('given direct relationAggregation', () => { const whenHookIsCalledWith = async (_entity: Entity) => { const { result } = renderHook( ({ entity }) => useGetEntities(entity, 'direct'), diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts index 5a708bcfee..d806bbfef2 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts @@ -125,11 +125,11 @@ const getChildOwnershipEntityRefs = async ( const getOwners = async ( entity: Entity, - relations: EntityRelationAggregation, + relationAggregation: EntityRelationAggregation, catalogApi: CatalogApi, ): Promise => { const isGroup = entity.kind === 'Group'; - const isAggregated = relations === 'aggregated'; + const isAggregated = relationAggregation === 'aggregated'; const isUserEntity = entity.kind === 'User'; if (isAggregated && isGroup) { @@ -166,7 +166,7 @@ const getOwnedEntitiesByOwners = ( export function useGetEntities( entity: Entity, - relations: EntityRelationAggregation, + relationAggregation: EntityRelationAggregation, entityFilterKind?: string[], entityLimit = 6, ): { @@ -189,7 +189,7 @@ export function useGetEntities( error, value: componentsWithCounters, } = useAsync(async () => { - const owners = await getOwners(entity, relations, catalogApi); + const owners = await getOwners(entity, relationAggregation, catalogApi); const ownedEntitiesList = await getOwnedEntitiesByOwners( owners, @@ -230,7 +230,7 @@ export function useGetEntities( kind: string; queryParams: string; }>; - }, [catalogApi, entity, relations]); + }, [catalogApi, entity, relationAggregation]); return { componentsWithCounters, From 6e11898ea2dda150e2bd9c58b2428e8e42f59cc6 Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Thu, 6 Jun 2024 14:56:30 +0100 Subject: [PATCH 043/860] Updating template input documentation Signed-off-by: Tavi Nolan --- .../software-templates/input-examples.md | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/features/software-templates/input-examples.md b/docs/features/software-templates/input-examples.md index a95cee24f4..32d37ae17c 100644 --- a/docs/features/software-templates/input-examples.md +++ b/docs/features/software-templates/input-examples.md @@ -238,3 +238,51 @@ spec: input: url: ${{ parameters.path if parameters.path else '/root' }} ``` + +## Use placeholders to reference remote files + +#### Note: testing of this functionality is not yet supported using _create/edit_ + +### template.yaml + +```yaml +spec: + parameters: + - $yaml: https://github.com/example/path/to/example.yaml + - title: Fill in some steps + properties: + path: + title: path + type: string + + steps: + - $yaml: https://github.com//example/path/to/action.yaml + + - id: fetch + name: Fetch template + action: fetch:template + input: + url: ${{ parameters.path if parameters.path else '/root' }} +``` + +### example.yaml + +```yaml +title: Provide simple information +required: + - url +properties: + url: + title: url + type: string +``` + +### action.yaml + +```yaml +id: publish +name: Publish files +action: publish:github +input: + repoUrl: ${{ parameters.url }} +``` From 3a5d011ded51423947b861f0d0b0663e34944a78 Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Fri, 7 Jun 2024 11:51:14 +0530 Subject: [PATCH 044/860] 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 eb6a71523accc4bb4621cf7f5891490a53ea04ad Mon Sep 17 00:00:00 2001 From: Emile Fokkema Date: Fri, 7 Jun 2024 20:55:00 +0000 Subject: [PATCH 045/860] add failing test Signed-off-by: Emile Fokkema --- .../src/components/Select/Select.test.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/core-components/src/components/Select/Select.test.tsx b/packages/core-components/src/components/Select/Select.test.tsx index 71159150e4..e5651ca47f 100644 --- a/packages/core-components/src/components/Select/Select.test.tsx +++ b/packages/core-components/src/components/Select/Select.test.tsx @@ -55,6 +55,25 @@ describe(', + ); + + expect(getByTestId('select').textContent).toBe(initialValue); + + rerender(, From eb60b321bbe91d75170bf7436b8bf78b62eb6493 Mon Sep 17 00:00:00 2001 From: Emile Fokkema Date: Fri, 7 Jun 2024 20:56:59 +0000 Subject: [PATCH 046/860] make test pass Signed-off-by: Emile Fokkema --- packages/core-components/src/components/Select/Select.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 924b49f640..00fb4f21b4 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -254,7 +254,7 @@ export function SelectComponent(props: SelectProps) { getContentAnchorEl: null, }} > - {placeholder && !multiple && ( + {!!placeholder && !multiple && ( {placeholder} )} {native From d4ffdbbce3e76ead5ea97ded0b89a08b2f742533 Mon Sep 17 00:00:00 2001 From: Emile Fokkema Date: Fri, 7 Jun 2024 20:57:58 +0000 Subject: [PATCH 047/860] add changeset Signed-off-by: Emile Fokkema --- .changeset/eighty-games-wink.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eighty-games-wink.md diff --git a/.changeset/eighty-games-wink.md b/.changeset/eighty-games-wink.md new file mode 100644 index 0000000000..46df27d16f --- /dev/null +++ b/.changeset/eighty-games-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Fixed bug where component with empty string as placeholder gave error +Fixed bug where ` onChange({ project: e.target.value })} - value={project} - onBlur={() => onChangeProject()} - /> - + { + onChange({ project: newValue || '' }); + }} + options={availableProjects} + renderInput={params => } + freeSolo + onBlur={() => onChangeProject()} + autoSelect + /> )} The Project that this repo will belong to From 0aaf020359d48d57074ca259e59d1c47ee96de17 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 7 Jun 2024 13:15:14 +0200 Subject: [PATCH 062/860] feat: add auto-completion to workspaces and repositories Signed-off-by: Benjamin Janssens --- .../src/BitbucketCloudClient.ts | 10 ++ .../src/models/index.ts | 11 ++ .../RepoUrlPicker/BitbucketRepoPicker.tsx | 133 +++++++++++------- .../fields/RepoUrlPicker/RepoUrlPicker.tsx | 1 + .../RepoUrlPicker/RepoUrlPickerRepoName.tsx | 26 ++-- .../components/fields/RepoUrlPicker/types.ts | 1 + 6 files changed, 124 insertions(+), 58 deletions(-) diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts index 97d3d0e52e..a06f7425d0 100644 --- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts +++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts @@ -85,6 +85,16 @@ export class BitbucketCloudClient { ); } + listWorkspaces( + options?: FilterAndSortOptions & PartialResponseOptions, + ): WithPagination { + return new WithPagination( + paginationOptions => + this.createUrl('/workspaces', { ...paginationOptions, ...options }), + url => this.getTypeMapped(url), + ); + } + private createUrl(endpoint: string, options?: RequestOptions): URL { const request = new URL(this.config.apiBaseUrl + endpoint); for (const key in options) { diff --git a/plugins/bitbucket-cloud-common/src/models/index.ts b/plugins/bitbucket-cloud-common/src/models/index.ts index ace8ee4939..2cdc143d06 100644 --- a/plugins/bitbucket-cloud-common/src/models/index.ts +++ b/plugins/bitbucket-cloud-common/src/models/index.ts @@ -264,6 +264,17 @@ export namespace Models { values?: Set; } + /** + * A paginated list of workspaces. + * @public + */ + export interface PaginatedWorkspaces extends Paginated { + /** + * The values of the current page. + */ + values?: Set; + } + /** * Object describing a user's role on resources like commits or pull requests. * @public diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 75ae840407..a7c2efc75e 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -17,8 +17,6 @@ import React, { useEffect, useState } from 'react'; 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 { Select, SelectItem } from '@backstage/core-components'; import { RepoUrlPickerState } from './types'; import { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; @@ -65,10 +63,8 @@ export const BitbucketRepoPicker = (props: { }, [allowedOwners, host, onChange]); const [client, setClient] = useState(); + const [availableWorkspaces, setAvailableWorkspaces] = useState([]); const [availableProjects, setAvailableProjects] = useState([]); - const [availableRepositories, setAvailableRepositories] = useState( - [], - ); useEffect(() => { if (accessToken) @@ -81,39 +77,78 @@ export const BitbucketRepoPicker = (props: { ); }, [accessToken]); - const onChangeWorkspace = async () => { - if (client) - if (!workspace) { - setAvailableProjects([]); - } else { - try { - for await (const page of client - .listProjectsByWorkspace(workspace) - .iteratePages()) { - const keys = [...page.values!].map(p => p.key!); - setAvailableProjects([...availableProjects, ...keys]); - } - } catch { - setAvailableProjects([]); - } - } - }; + // Update available workspaces when host changes + useEffect(() => { + const updateAvailableWorkspaces = async () => { + if (client) + if (!host) { + setAvailableWorkspaces([]); + } else { + const result: string[] = []; - const onChangeProject = async () => { - if (client && workspace) - if (!project) { - setAvailableRepositories([]); - } else { - for await (const page of client - .listRepositoriesByWorkspace(workspace, { - q: `project.key="${project}"`, - }) - .iteratePages()) { - const keys = [...page.values!].map(p => p.slug!); - setAvailableRepositories([...availableRepositories, ...keys]); + for await (const page of client.listWorkspaces().iteratePages()) { + const keys = [...page.values!].map(p => p.slug!); + result.push(...keys); + } + + setAvailableWorkspaces(result); } - } - }; + }; + + updateAvailableWorkspaces(); + }, [client, host]); + + // Update available repositories when workspace or project changes + useEffect(() => { + const updateAvailableRepositories = async () => { + if (client && workspace) + if (!project) { + onChange({ availableRepos: [] }); + } else { + const availableRepos: string[] = []; + + for await (const page of client + .listRepositoriesByWorkspace(workspace, { + q: `project.key="${project}"`, + }) + .iteratePages()) { + const keys = [...page.values!].map(p => p.slug!); + availableRepos.push(...keys); + } + + onChange({ availableRepos }); + } + }; + + updateAvailableRepositories(); + }, [client, workspace, project, onChange]); + + // Update available projects when workspace changes + useEffect(() => { + const updateAvailableProjects = async () => { + if (client) + if (!workspace) { + setAvailableProjects([]); + } else { + try { + const result: string[] = []; + + for await (const page of client + .listProjectsByWorkspace(workspace) + .iteratePages()) { + const keys = [...page.values!].map(p => p.key!); + result.push(...keys); + } + + setAvailableProjects(result); + } catch { + setAvailableProjects([]); + } + } + }; + + updateAvailableProjects(); + }, [client, workspace]); return ( <> @@ -135,15 +170,18 @@ export const BitbucketRepoPicker = (props: { items={ownerItems} /> ) : ( - <> - Workspace - onChange({ workspace: e.target.value })} - value={workspace} - onBlur={() => onChangeWorkspace()} - /> - + { + onChange({ workspace: newValue || '' }); + }} + options={availableWorkspaces} + renderInput={params => ( + + )} + freeSolo + autoSelect + /> )} The Workspace that this repo will belong to @@ -173,9 +211,10 @@ export const BitbucketRepoPicker = (props: { onChange({ project: newValue || '' }); }} options={availableProjects} - renderInput={params => } + renderInput={params => ( + + )} freeSolo - onBlur={() => onChangeProject()} autoSelect /> )} diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index cd749a08a1..e0d714ffda 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -232,6 +232,7 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => { setState(prevState => ({ ...prevState, repoName: repo })) } rawErrors={rawErrors} + availableRepos={state.availableRepos} /> ); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx index f2d68b08f3..80851b0cbb 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx @@ -17,16 +17,17 @@ import React, { useEffect } from 'react'; import { Select, SelectItem } from '@backstage/core-components'; 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 Autocomplete from '@material-ui/lab/Autocomplete'; +import TextField from '@material-ui/core/TextField'; export const RepoUrlPickerRepoName = (props: { repoName?: string; allowedRepos?: string[]; onChange: (host: string) => void; rawErrors: string[]; + availableRepos?: string[]; }) => { - const { repoName, allowedRepos, onChange, rawErrors } = props; + const { repoName, allowedRepos, onChange, rawErrors, availableRepos } = props; useEffect(() => { // If there is no repoName chosen currently @@ -61,14 +62,17 @@ export const RepoUrlPickerRepoName = (props: { items={repoItems} /> ) : ( - <> - Repository - onChange(String(e.target.value))} - value={repoName} - /> - + { + onChange(newValue || ''); + }} + options={availableRepos || []} + renderInput={params => ( + + )} + freeSolo + /> )} The name of the repository diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts index 5e979e789e..1430b10b84 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts @@ -20,4 +20,5 @@ export interface RepoUrlPickerState { organization?: string; workspace?: string; project?: string; + availableRepos?: string[]; } From c9af3ea5e2d8d377c2ea68f9a1de9b283923a10d Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 7 Jun 2024 13:44:37 +0200 Subject: [PATCH 063/860] test: add tests for BitbucketCloudClient Signed-off-by: Benjamin Janssens --- .../src/BitbucketCloudClient.test.ts | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts index c5c0d604be..92e3261410 100644 --- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts +++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts @@ -107,4 +107,59 @@ describe('BitbucketCloudClient', () => { expect(results).toHaveLength(1); expect(results[0].slug).toEqual('repo1'); }); + + it('listProjectsByWorkspace', async () => { + server.use( + rest.get( + 'https://api.bitbucket.org/2.0/workspaces/ws/projects', + (_, res, ctx) => { + const response = { + values: [ + { + type: 'repository', + slug: 'project1', + } as Models.Project, + ], + }; + return res(ctx.json(response)); + }, + ), + ); + + const pagination = client.listProjectsByWorkspace('ws'); + + const results = []; + for await (const result of pagination.iterateResults()) { + results.push(result); + } + + expect(results).toHaveLength(1); + expect(results[0].slug).toEqual('project1'); + }); + + it('listWorkspaces', async () => { + server.use( + rest.get('https://api.bitbucket.org/2.0/workspaces', (_, res, ctx) => { + const response = { + values: [ + { + type: 'workspace', + slug: 'workspace1', + } as Models.Workspace, + ], + }; + return res(ctx.json(response)); + }), + ); + + const pagination = client.listWorkspaces(); + + const results = []; + for await (const result of pagination.iterateResults()) { + results.push(result); + } + + expect(results).toHaveLength(1); + expect(results[0].slug).toEqual('workspace1'); + }); }); From 0c5a38e854f37125c33cf8554929ba2062b7fe37 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 7 Jun 2024 15:48:34 +0200 Subject: [PATCH 064/860] fix: use onInputChange and useDebounce Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 111 ++++++++++-------- .../RepoUrlPicker/RepoUrlPickerRepoName.tsx | 2 +- 2 files changed, 61 insertions(+), 52 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index a7c2efc75e..abbbe7a8e4 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -22,6 +22,7 @@ import { RepoUrlPickerState } from './types'; import { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; import Autocomplete from '@material-ui/lab/Autocomplete'; import TextField from '@material-ui/core/TextField'; +import useDebounce from 'react-use/esm/useDebounce'; /** * The underlying component that is rendered in the form for the `BitbucketRepoPicker` @@ -78,59 +79,67 @@ export const BitbucketRepoPicker = (props: { }, [accessToken]); // Update available workspaces when host changes - useEffect(() => { - const updateAvailableWorkspaces = async () => { - if (client) - if (!host) { - setAvailableWorkspaces([]); - } else { - const result: string[] = []; + useDebounce( + () => { + const updateAvailableWorkspaces = async () => { + if (client) + if (!host) { + setAvailableWorkspaces([]); + } else { + const result: string[] = []; - for await (const page of client.listWorkspaces().iteratePages()) { - const keys = [...page.values!].map(p => p.slug!); - result.push(...keys); + for await (const page of client.listWorkspaces().iteratePages()) { + const keys = [...page.values!].map(p => p.slug!); + result.push(...keys); + } + + setAvailableWorkspaces(result); } + }; - setAvailableWorkspaces(result); - } - }; - - updateAvailableWorkspaces(); - }, [client, host]); + updateAvailableWorkspaces(); + }, + 500, + [client, host], + ); // Update available repositories when workspace or project changes - useEffect(() => { - const updateAvailableRepositories = async () => { - if (client && workspace) - if (!project) { - onChange({ availableRepos: [] }); - } else { - const availableRepos: string[] = []; + useDebounce( + () => { + const updateAvailableRepositories = async () => { + if (client && workspace) + if (!project) { + onChange({ availableRepos: [] }); + } else { + const availableRepos: string[] = []; - for await (const page of client - .listRepositoriesByWorkspace(workspace, { - q: `project.key="${project}"`, - }) - .iteratePages()) { - const keys = [...page.values!].map(p => p.slug!); - availableRepos.push(...keys); + for await (const page of client + .listRepositoriesByWorkspace(workspace, { + q: `project.key="${project}"`, + }) + .iteratePages()) { + const keys = [...page.values!].map(p => p.slug!); + availableRepos.push(...keys); + } + + onChange({ availableRepos }); } + }; - onChange({ availableRepos }); - } - }; - - updateAvailableRepositories(); - }, [client, workspace, project, onChange]); + updateAvailableRepositories(); + }, + 500, + [client, workspace, project, onChange], + ); // Update available projects when workspace changes - useEffect(() => { - const updateAvailableProjects = async () => { - if (client) - if (!workspace) { - setAvailableProjects([]); - } else { - try { + useDebounce( + () => { + const updateAvailableProjects = async () => { + if (client) + if (!workspace) { + setAvailableProjects([]); + } else { const result: string[] = []; for await (const page of client @@ -141,14 +150,14 @@ export const BitbucketRepoPicker = (props: { } setAvailableProjects(result); - } catch { - setAvailableProjects([]); } - } - }; + }; - updateAvailableProjects(); - }, [client, workspace]); + updateAvailableProjects(); + }, + 500, + [client, workspace], + ); return ( <> @@ -172,7 +181,7 @@ export const BitbucketRepoPicker = (props: { ) : ( { + onInputChange={(_, newValue) => { onChange({ workspace: newValue || '' }); }} options={availableWorkspaces} @@ -207,7 +216,7 @@ export const BitbucketRepoPicker = (props: { ) : ( { + onInputChange={(_, newValue) => { onChange({ project: newValue || '' }); }} options={availableProjects} diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx index 80851b0cbb..0dcff7e6fc 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx @@ -64,7 +64,7 @@ export const RepoUrlPickerRepoName = (props: { ) : ( { + onInputChange={(_, newValue) => { onChange(newValue || ''); }} options={availableRepos || []} From be26d90de13b2aaca2e52417247dab18ffd494d0 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 7 Jun 2024 15:52:45 +0200 Subject: [PATCH 065/860] fix: improve error handling Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index abbbe7a8e4..3bcb94d2f6 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -97,7 +97,11 @@ export const BitbucketRepoPicker = (props: { } }; - updateAvailableWorkspaces(); + try { + updateAvailableWorkspaces(); + } catch { + setAvailableWorkspaces([]); + } }, 500, [client, host], @@ -126,7 +130,11 @@ export const BitbucketRepoPicker = (props: { } }; - updateAvailableRepositories(); + try { + updateAvailableRepositories(); + } catch { + onChange({ availableRepos: [] }); + } }, 500, [client, workspace, project, onChange], @@ -153,7 +161,11 @@ export const BitbucketRepoPicker = (props: { } }; - updateAvailableProjects(); + try { + updateAvailableProjects(); + } catch { + setAvailableProjects([]); + } }, 500, [client, workspace], From f0781a53940ba3942a8fe81af0d6db0e4b699c57 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 7 Jun 2024 16:46:36 +0200 Subject: [PATCH 066/860] fix: make error handling work; add tests for RepoUrlPickerRepoName Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 20 ++++--------- .../RepoUrlPickerRepoName.test.tsx | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 3bcb94d2f6..a56e1ad9ad 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -97,11 +97,7 @@ export const BitbucketRepoPicker = (props: { } }; - try { - updateAvailableWorkspaces(); - } catch { - setAvailableWorkspaces([]); - } + updateAvailableWorkspaces().catch(() => setAvailableWorkspaces([])); }, 500, [client, host], @@ -130,11 +126,9 @@ export const BitbucketRepoPicker = (props: { } }; - try { - updateAvailableRepositories(); - } catch { - onChange({ availableRepos: [] }); - } + updateAvailableRepositories().catch(() => + onChange({ availableRepos: [] }), + ); }, 500, [client, workspace, project, onChange], @@ -161,11 +155,7 @@ export const BitbucketRepoPicker = (props: { } }; - try { - updateAvailableProjects(); - } catch { - setAvailableProjects([]); - } + updateAvailableProjects().catch(() => setAvailableProjects([])); }, 500, [client, workspace], diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx index 4c392d646c..8228f443df 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx @@ -16,6 +16,7 @@ import React from 'react'; import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; import { render, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; describe('RepoUrlPickerRepoName', () => { it('should call onChange with the first allowed repo if there is none set already', async () => { @@ -73,4 +74,31 @@ describe('RepoUrlPickerRepoName', () => { expect(onChange).toHaveBeenCalledWith('foo'); }); + + it('should autocomplete with provided availableRepos', async () => { + const availableRepos = ['foo', 'bar']; + + const onChange = jest.fn(); + + const { getByRole, getByText } = render( + , + ); + + // Open the Autocomplete dropdown + const input = getByRole('textbox'); + await userEvent.click(input); + + // Verify that available repos are shown + for (const repo of availableRepos) { + expect(getByText(repo)).toBeInTheDocument(); + } + + // Verify that selecting an option calls onChange + await userEvent.click(getByText('foo')); + expect(onChange).toHaveBeenCalledWith('foo'); + }); }); From f78b919bf093fd3f1d462f61c587a018b88878bd Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 10 Jun 2024 13:10:44 +0200 Subject: [PATCH 067/860] test: add tests for BitbucketRepoPicker Signed-off-by: Benjamin Janssens --- .../src/BitbucketCloudClient.test.ts | 2 +- .../BitbucketRepoPicker.test.tsx | 133 +++++++++++++++++- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 54 +++---- 3 files changed, 160 insertions(+), 29 deletions(-) diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts index 92e3261410..f625f0daf8 100644 --- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts +++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts @@ -116,7 +116,7 @@ describe('BitbucketCloudClient', () => { const response = { values: [ { - type: 'repository', + type: 'project', slug: 'project1', } as Models.Project, ], diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index f799d68c2d..9dae5b24a6 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -16,7 +16,13 @@ import React from 'react'; import { BitbucketRepoPicker } from './BitbucketRepoPicker'; -import { render, fireEvent } from '@testing-library/react'; +import { render, fireEvent, waitFor } from '@testing-library/react'; +import { setupServer } from 'msw/node'; +import { rest } from 'msw'; +import { Models } from '@backstage/plugin-bitbucket-cloud-common'; +import userEvent from '@testing-library/user-event'; + +const server = setupServer(); describe('BitbucketRepoPicker', () => { it('renders a select if there is a list of allowed owners', async () => { @@ -136,4 +142,129 @@ describe('BitbucketRepoPicker', () => { expect(await findByText('project2')).toBeInTheDocument(); }); }); + + describe('autocompletion', () => { + beforeAll(() => server.listen({ onUnhandledRequest: 'error' })); + beforeEach(() => { + // BitbucketCloudClient.listWorkspaces() + server.use( + rest.get('https://api.bitbucket.org/2.0/workspaces', (_, res, ctx) => { + const response = { + values: [ + { + type: 'workspace', + slug: 'workspace1', + } as Models.Workspace, + ], + }; + return res(ctx.json(response)); + }), + ); + + // BitbucketCloudClient.listProjectsByWorkspace() + server.use( + rest.get( + 'https://api.bitbucket.org/2.0/workspaces/workspace1/projects', + (_, res, ctx) => { + const response = { + values: [ + { + type: 'project', + key: 'project1', + } as Models.Project, + ], + }; + return res(ctx.json(response)); + }, + ), + ); + + // BitbucketCloudClient.listRepositoriesByWorkspace() + server.use( + rest.get( + 'https://api.bitbucket.org/2.0/repositories/workspace1', + (_, res, ctx) => { + const response = { + values: [ + { + type: 'repository', + slug: 'repo1', + } as Models.Repository, + ], + }; + return res(ctx.json(response)); + }, + ), + ); + }); + afterAll(() => server.close()); + afterEach(() => server.resetHandlers()); + + it('should populate workspaces if host is set and accessToken is provided', async () => { + const onChange = jest.fn(); + const { getAllByRole, getByText } = render( + , + ); + + // Open the Autcomplete dropdown + const workspaceInput = getAllByRole('textbox')[0]; + await userEvent.click(workspaceInput); + + // Verify that the available workspaces are shown + await waitFor(() => expect(getByText('workspace1')).toBeInTheDocument()); + + // Verify that selecting an option calls onChange + await userEvent.click(getByText('workspace1')); + expect(onChange).toHaveBeenCalledWith({ workspace: 'workspace1' }); + }); + + it('should populate projects if host and workspace are set and accessToken is provided', async () => { + const onChange = jest.fn(); + const { getAllByRole, getByText } = render( + , + ); + + // Open the Autcomplete dropdown + const projectInput = getAllByRole('textbox')[1]; + await userEvent.click(projectInput); + + // Verify that the available projects are shown + await waitFor(() => expect(getByText('project1')).toBeInTheDocument()); + + // Verify that selecting an option calls onChange + await userEvent.click(getByText('project1')); + expect(onChange).toHaveBeenCalledWith({ project: 'project1' }); + }); + + it('should populate repositories if host, workspace and project are set and accessToken is provided', async () => { + const onChange = jest.fn(); + render( + , + ); + + // Verify that the available repos are updated + await waitFor(() => + expect(onChange).toHaveBeenCalledWith({ availableRepos: ['repo1'] }), + ); + }); + }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index a56e1ad9ad..67e82abc3f 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -103,6 +103,33 @@ export const BitbucketRepoPicker = (props: { [client, host], ); + // Update available projects when workspace changes + useDebounce( + () => { + const updateAvailableProjects = async () => { + if (client) + if (!workspace) { + setAvailableProjects([]); + } else { + const result: string[] = []; + + for await (const page of client + .listProjectsByWorkspace(workspace) + .iteratePages()) { + const keys = [...page.values!].map(p => p.key!); + result.push(...keys); + } + + setAvailableProjects(result); + } + }; + + updateAvailableProjects().catch(() => setAvailableProjects([])); + }, + 500, + [client, workspace], + ); + // Update available repositories when workspace or project changes useDebounce( () => { @@ -134,33 +161,6 @@ export const BitbucketRepoPicker = (props: { [client, workspace, project, onChange], ); - // Update available projects when workspace changes - useDebounce( - () => { - const updateAvailableProjects = async () => { - if (client) - if (!workspace) { - setAvailableProjects([]); - } else { - const result: string[] = []; - - for await (const page of client - .listProjectsByWorkspace(workspace) - .iteratePages()) { - const keys = [...page.values!].map(p => p.key!); - result.push(...keys); - } - - setAvailableProjects(result); - } - }; - - updateAvailableProjects().catch(() => setAvailableProjects([])); - }, - 500, - [client, workspace], - ); - return ( <> {host === 'bitbucket.org' && ( From da3db7945a699f77ff64ff27ffbc5e03dcceb877 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 10 Jun 2024 13:47:00 +0200 Subject: [PATCH 068/860] chore: clean up some code Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 80 +++++++++---------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 67e82abc3f..5361b99b01 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-restricted-syntax */ /* * Copyright 2021 The Backstage Authors * @@ -82,19 +81,18 @@ export const BitbucketRepoPicker = (props: { useDebounce( () => { const updateAvailableWorkspaces = async () => { - if (client) - if (!host) { - setAvailableWorkspaces([]); - } else { - const result: string[] = []; + if (client && host) { + const result: string[] = []; - for await (const page of client.listWorkspaces().iteratePages()) { - const keys = [...page.values!].map(p => p.slug!); - result.push(...keys); - } - - setAvailableWorkspaces(result); + for await (const page of client.listWorkspaces().iteratePages()) { + const keys = [...page.values!].map(p => p.slug!); + result.push(...keys); } + + setAvailableWorkspaces(result); + } else { + setAvailableWorkspaces([]); + } }; updateAvailableWorkspaces().catch(() => setAvailableWorkspaces([])); @@ -107,21 +105,20 @@ export const BitbucketRepoPicker = (props: { useDebounce( () => { const updateAvailableProjects = async () => { - if (client) - if (!workspace) { - setAvailableProjects([]); - } else { - const result: string[] = []; + if (client && workspace) { + const result: string[] = []; - for await (const page of client - .listProjectsByWorkspace(workspace) - .iteratePages()) { - const keys = [...page.values!].map(p => p.key!); - result.push(...keys); - } - - setAvailableProjects(result); + for await (const page of client + .listProjectsByWorkspace(workspace) + .iteratePages()) { + const keys = [...page.values!].map(p => p.key!); + result.push(...keys); } + + setAvailableProjects(result); + } else { + setAvailableProjects([]); + } }; updateAvailableProjects().catch(() => setAvailableProjects([])); @@ -134,23 +131,22 @@ export const BitbucketRepoPicker = (props: { useDebounce( () => { const updateAvailableRepositories = async () => { - if (client && workspace) - if (!project) { - onChange({ availableRepos: [] }); - } else { - const availableRepos: string[] = []; + if (client && workspace && project) { + const availableRepos: string[] = []; - for await (const page of client - .listRepositoriesByWorkspace(workspace, { - q: `project.key="${project}"`, - }) - .iteratePages()) { - const keys = [...page.values!].map(p => p.slug!); - availableRepos.push(...keys); - } - - onChange({ availableRepos }); + for await (const page of client + .listRepositoriesByWorkspace(workspace, { + q: `project.key="${project}"`, + }) + .iteratePages()) { + const keys = [...page.values!].map(p => p.slug!); + availableRepos.push(...keys); } + + onChange({ availableRepos }); + } else { + onChange({ availableRepos: [] }); + } }; updateAvailableRepositories().catch(() => @@ -184,7 +180,7 @@ export const BitbucketRepoPicker = (props: { { - onChange({ workspace: newValue || '' }); + onChange({ workspace: String(newValue) }); }} options={availableWorkspaces} renderInput={params => ( @@ -219,7 +215,7 @@ export const BitbucketRepoPicker = (props: { { - onChange({ project: newValue || '' }); + onChange({ project: String(newValue) }); }} options={availableProjects} renderInput={params => ( From 7bc44a99e6df85e22017e4bdb723beb1d9e30901 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 10 Jun 2024 14:25:51 +0200 Subject: [PATCH 069/860] chore: make client dependent on host Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 5361b99b01..72c39fb11c 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -67,21 +67,24 @@ export const BitbucketRepoPicker = (props: { const [availableProjects, setAvailableProjects] = useState([]); useEffect(() => { - if (accessToken) + if (host === 'bitbucket.org' && accessToken) { setClient( BitbucketCloudClient.fromConfig({ - host: 'bitbucket.org', + host, apiBaseUrl: 'https://api.bitbucket.org/2.0', accessToken, }), ); - }, [accessToken]); + } else { + setClient(undefined); + } + }, [host, accessToken]); - // Update available workspaces when host changes + // Update available workspaces when client is available useDebounce( () => { const updateAvailableWorkspaces = async () => { - if (client && host) { + if (client) { const result: string[] = []; for await (const page of client.listWorkspaces().iteratePages()) { @@ -98,10 +101,10 @@ export const BitbucketRepoPicker = (props: { updateAvailableWorkspaces().catch(() => setAvailableWorkspaces([])); }, 500, - [client, host], + [client], ); - // Update available projects when workspace changes + // Update available projects when client is available and workspace changes useDebounce( () => { const updateAvailableProjects = async () => { @@ -127,7 +130,7 @@ export const BitbucketRepoPicker = (props: { [client, workspace], ); - // Update available repositories when workspace or project changes + // Update available repositories when client is available and workspace or project changes useDebounce( () => { const updateAvailableRepositories = async () => { From 2127b5ef04c87ea25b31dd9ee47a0723db3243b6 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 10 Jun 2024 14:44:40 +0200 Subject: [PATCH 070/860] chore: update API reports Signed-off-by: Benjamin Janssens --- packages/integration/api-report.md | 1 + plugins/bitbucket-cloud-common/api-report.md | 15 +++++++++++++++ .../RepoUrlPicker/RepoUrlPickerRepoName.tsx | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/integration/api-report.md b/packages/integration/api-report.md index f9a8426cf5..91abc7473f 100644 --- a/packages/integration/api-report.md +++ b/packages/integration/api-report.md @@ -186,6 +186,7 @@ export type BitbucketCloudIntegrationConfig = { apiBaseUrl: string; username?: string; appPassword?: string; + accessToken?: string; }; // @public @deprecated diff --git a/plugins/bitbucket-cloud-common/api-report.md b/plugins/bitbucket-cloud-common/api-report.md index 0f4e82d5d1..34c245facc 100644 --- a/plugins/bitbucket-cloud-common/api-report.md +++ b/plugins/bitbucket-cloud-common/api-report.md @@ -12,11 +12,20 @@ export class BitbucketCloudClient { config: BitbucketCloudIntegrationConfig, ): BitbucketCloudClient; // (undocumented) + listProjectsByWorkspace( + workspace: string, + options?: FilterAndSortOptions & PartialResponseOptions, + ): WithPagination; + // (undocumented) listRepositoriesByWorkspace( workspace: string, options?: FilterAndSortOptions & PartialResponseOptions, ): WithPagination; // (undocumented) + listWorkspaces( + options?: FilterAndSortOptions & PartialResponseOptions, + ): WithPagination; + // (undocumented) searchCode( workspace: string, query: string, @@ -200,9 +209,15 @@ export namespace Models { size?: number; values?: Array | Set; } + export interface PaginatedProjects extends Paginated { + values?: Set; + } export interface PaginatedRepositories extends Paginated { values?: Set; } + export interface PaginatedWorkspaces extends Paginated { + values?: Set; + } export interface Participant extends ModelObject { // (undocumented) approved?: boolean; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx index 0dcff7e6fc..cd346cf8ed 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx @@ -65,7 +65,7 @@ export const RepoUrlPickerRepoName = (props: { { - onChange(newValue || ''); + onChange(String(newValue)); }} options={availableRepos || []} renderInput={params => ( From 0757000fad2a3ab99efd5811d7a8b428f883b6cf Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 11 Jun 2024 12:09:58 +0200 Subject: [PATCH 071/860] chore: add changesets for plugin-bitbucket-cloud-common Signed-off-by: Benjamin Janssens --- .changeset/five-forks-retire.md | 5 +++++ .changeset/great-colts-enjoy.md | 5 +++++ .changeset/rare-planes-switch.md | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 .changeset/five-forks-retire.md create mode 100644 .changeset/great-colts-enjoy.md create mode 100644 .changeset/rare-planes-switch.md diff --git a/.changeset/five-forks-retire.md b/.changeset/five-forks-retire.md new file mode 100644 index 0000000000..9b9573bfd4 --- /dev/null +++ b/.changeset/five-forks-retire.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-bitbucket-cloud-common': patch +--- + +Added support for access tokens diff --git a/.changeset/great-colts-enjoy.md b/.changeset/great-colts-enjoy.md new file mode 100644 index 0000000000..6907f661a5 --- /dev/null +++ b/.changeset/great-colts-enjoy.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-bitbucket-cloud-common': patch +--- + +Added method `listProjectsByWorkspace` for retrieving projects by workspace diff --git a/.changeset/rare-planes-switch.md b/.changeset/rare-planes-switch.md new file mode 100644 index 0000000000..622c6d48d8 --- /dev/null +++ b/.changeset/rare-planes-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-bitbucket-cloud-common': patch +--- + +Added method `listWorkspaces` for retrieving workspaces From 5ecb6bc94258b91e2c75deea499881588dc039b1 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 11 Jun 2024 12:11:28 +0200 Subject: [PATCH 072/860] chore: add changesets for @backstage/integration Signed-off-by: Benjamin Janssens --- .changeset/nine-seals-sit.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nine-seals-sit.md diff --git a/.changeset/nine-seals-sit.md b/.changeset/nine-seals-sit.md new file mode 100644 index 0000000000..5ec46e30b3 --- /dev/null +++ b/.changeset/nine-seals-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Added support for access tokens to Bitbucket Cloud From 973ff9b74b51d64a075dc4c5874a4bb7fa023669 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 11 Jun 2024 12:13:29 +0200 Subject: [PATCH 073/860] chore: add changesets for @backstage/plugin-scaffolder Signed-off-by: Benjamin Janssens --- .changeset/angry-ladybugs-retire.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/angry-ladybugs-retire.md diff --git a/.changeset/angry-ladybugs-retire.md b/.changeset/angry-ladybugs-retire.md new file mode 100644 index 0000000000..eb6e8a5932 --- /dev/null +++ b/.changeset/angry-ladybugs-retire.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Added autocompletion for Bitbucket Cloud From d79cd670cca8fe1f28a84a8d91828e8482581b8e Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 11 Jun 2024 12:25:43 +0200 Subject: [PATCH 074/860] chore: set changesets for @backstage/plugin-scaffolder and @backstage/integration to minor Signed-off-by: Benjamin Janssens --- .changeset/angry-ladybugs-retire.md | 2 +- .changeset/nine-seals-sit.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/angry-ladybugs-retire.md b/.changeset/angry-ladybugs-retire.md index eb6e8a5932..ca2b34676b 100644 --- a/.changeset/angry-ladybugs-retire.md +++ b/.changeset/angry-ladybugs-retire.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder': minor --- Added autocompletion for Bitbucket Cloud diff --git a/.changeset/nine-seals-sit.md b/.changeset/nine-seals-sit.md index 5ec46e30b3..0055a1be24 100644 --- a/.changeset/nine-seals-sit.md +++ b/.changeset/nine-seals-sit.md @@ -1,5 +1,5 @@ --- -'@backstage/integration': patch +'@backstage/integration': minor --- Added support for access tokens to Bitbucket Cloud From 21ddf605221eb3109cdf795bae1e2b1bfdaa11c1 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 13 Jun 2024 11:51:57 +0200 Subject: [PATCH 075/860] feat: add endpoint for bitbucket autocomplete in scaffolder Signed-off-by: Benjamin Janssens --- plugins/scaffolder-backend/package.json | 1 + .../src/service/autocomplete.ts | 79 +++++++++++++++++++ .../scaffolder-backend/src/service/router.ts | 24 ++++++ yarn.lock | 1 + 4 files changed, 105 insertions(+) create mode 100644 plugins/scaffolder-backend/src/service/autocomplete.ts diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 4060529421..af6625c8b8 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -70,6 +70,7 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", diff --git a/plugins/scaffolder-backend/src/service/autocomplete.ts b/plugins/scaffolder-backend/src/service/autocomplete.ts new file mode 100644 index 0000000000..034a201450 --- /dev/null +++ b/plugins/scaffolder-backend/src/service/autocomplete.ts @@ -0,0 +1,79 @@ +/* + * 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 { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; + +export async function handleBitbucketCloudRequest( + token: string, + resource: string, + parameters: Record, +): Promise { + const client = BitbucketCloudClient.fromConfig({ + host: 'bitbucket.org', + apiBaseUrl: 'https://api.bitbucket.org/2.0', + accessToken: token, + }); + + switch (resource) { + case 'workspaces': { + const result: string[] = []; + + for await (const page of client.listWorkspaces().iteratePages()) { + const slugs = [...page.values!].map(p => p.slug!); + result.push(...slugs); + } + + return result; + } + case 'projects': { + if (!parameters.workspace) + throw new InputError('Missing workspace query parameter'); + + const result: string[] = []; + + for await (const page of client + .listProjectsByWorkspace(parameters.workspace) + .iteratePages()) { + const keys = [...page.values!].map(p => p.key!); + result.push(...keys); + } + + return result; + } + case 'repositories': { + if (!parameters.workspace || !parameters.project) + throw new InputError( + 'Missing workspace and/or project query parameter', + ); + + const result: string[] = []; + + for await (const page of client + .listRepositoriesByWorkspace(parameters.workspace, { + q: `project.key="${parameters.project}"`, + }) + .iteratePages()) { + const slugs = [...page.values!].map(p => p.slug!); + result.push(...slugs); + } + + return result; + } + default: + throw new InputError(`Invalid resource: ${resource}`); + } +} diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 384b9f5340..dbccd6ddb5 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -94,6 +94,7 @@ import { } from '@backstage/plugin-auth-node'; import { InternalTaskSecrets } from '../scaffolder/tasks/types'; import { checkPermission } from '../util/checkPermissions'; +import { handleBitbucketCloudRequest } from './autocomplete'; /** * @@ -771,6 +772,29 @@ export async function createRouter( base64Content: file.content.toString('base64'), })), }); + }) + .get('/v2/autocomplete/:provider/:resource', async (req, res) => { + const { token, ...query } = req.query; + const { provider, resource } = req.params; + + if (!token) throw new InputError('Missing token query parameter'); + + let result: string[]; + + switch (provider) { + case 'bitbucketCloud': { + result = await handleBitbucketCloudRequest( + token as string, + resource, + query as Record, + ); + break; + } + default: + throw new InputError(`Unsupported provider: ${provider}`); + } + + res.status(200).json(result); }); const app = express(); diff --git a/yarn.lock b/yarn.lock index 1719070c2f..7f44f1559c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7093,6 +7093,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/plugin-bitbucket-cloud-common": "workspace:^" "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" From 28c991d6e471eed1d73f679a4bb227b564b0d0ab Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 13 Jun 2024 12:53:50 +0200 Subject: [PATCH 076/860] test: add tests for autocomplete endpoint Signed-off-by: Benjamin Janssens --- .../src/service/router.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 8ba26c68a4..0024a57bd9 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -46,6 +46,7 @@ import { PermissionEvaluator, } from '@backstage/plugin-permission-common'; import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; +import { handleBitbucketCloudRequest } from './autocomplete'; const mockAccess = jest.fn(); @@ -62,6 +63,10 @@ jest.mock('fs-extra', () => ({ remove: jest.fn(), })); +jest.mock('./autocomplete', () => ({ + handleBitbucketCloudRequest: jest.fn(), +})); + function createDatabase(): PluginDatabaseManager { return DatabaseManager.fromConfig( new ConfigReader({ @@ -1461,5 +1466,22 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(subscriber!.closed).toBe(true); }); }); + + describe('GET /v2/autocomplete/:provider/:resource', () => { + it('should handle requests for provider bitbucketCloud', async () => { + const bbToken = 'foo'; + const resource = 'bar'; + + await request(app) + .get(`/v2/autocomplete/bitbucketCloud/${resource}?token=${bbToken}`) + .send(); + + expect(jest.mocked(handleBitbucketCloudRequest)).toHaveBeenCalledWith( + bbToken, + resource, + {}, + ); + }); + }); }); }); From 8a03156d9165f3747eae3d9b8a19105c7b12606e Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 13 Jun 2024 14:58:38 +0200 Subject: [PATCH 077/860] feat: use autocomplete endpoint in frontend Signed-off-by: Benjamin Janssens --- plugins/scaffolder-react/src/api/types.ts | 7 + .../components/Workflow/Workflow.test.tsx | 1 + plugins/scaffolder/package.json | 1 - plugins/scaffolder/src/api.ts | 24 ++ .../BitbucketRepoPicker.test.tsx | 240 +++++++++--------- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 73 ++---- .../TemplateWizardPage.test.tsx | 1 + yarn.lock | 1 - 8 files changed, 175 insertions(+), 173 deletions(-) diff --git a/plugins/scaffolder-react/src/api/types.ts b/plugins/scaffolder-react/src/api/types.ts index b4a3deea54..c79f98c780 100644 --- a/plugins/scaffolder-react/src/api/types.ts +++ b/plugins/scaffolder-react/src/api/types.ts @@ -229,4 +229,11 @@ export interface ScaffolderApi { streamLogs(options: ScaffolderStreamLogsOptions): Observable; dryRun?(options: ScaffolderDryRunOptions): Promise; + + autocomplete( + token: string, + provider: string, + resource: string, + params?: Record, + ): Promise; } diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx index 27fde2083f..3a2aa1469f 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx @@ -36,6 +36,7 @@ const scaffolderApiMock: jest.Mocked = { streamLogs: jest.fn(), listActions: jest.fn(), listTasks: jest.fn(), + autocomplete: jest.fn(), }; const catalogApiMock: jest.Mocked = { getEntityByRef: jest.fn(), diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index a17fc14105..d1b58c8eca 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -67,7 +67,6 @@ "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/integration-react": "workspace:^", - "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index 6ef5fff588..ff5c89e91e 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -337,4 +337,28 @@ export class ScaffolderClient implements ScaffolderApi { return await response.json(); } + + async autocomplete( + token: string, + provider: string, + resource: string, + params?: Record, + ): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); + const query = new URLSearchParams({ + ...params, + token, + }); + const url = `${baseUrl}/v2/autocomplete/${provider}/${resource}?${query}`; + + const response = await this.fetchApi.fetch(url, { + method: 'GET', + }); + + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + return await response.json(); + } } diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index 9dae5b24a6..404fb6ddf6 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -17,23 +17,33 @@ import React from 'react'; import { BitbucketRepoPicker } from './BitbucketRepoPicker'; import { render, fireEvent, waitFor } from '@testing-library/react'; -import { setupServer } from 'msw/node'; -import { rest } from 'msw'; -import { Models } from '@backstage/plugin-bitbucket-cloud-common'; import userEvent from '@testing-library/user-event'; - -const server = setupServer(); +import { TestApiProvider } from '@backstage/test-utils'; +import { + ScaffolderApi, + scaffolderApiRef, +} from '@backstage/plugin-scaffolder-react'; describe('BitbucketRepoPicker', () => { + const scaffolderApiMock: Partial = { + autocomplete: jest + .fn() + .mockImplementation((_token, _provider, resource) => [ + `${resource}_example`, + ]), + }; + it('renders a select if there is a list of allowed owners', async () => { const allowedOwners = ['owner1', 'owner2']; const { findByText } = render( - , + + + , ); expect(await findByText('owner1')).toBeInTheDocument(); @@ -44,7 +54,13 @@ describe('BitbucketRepoPicker', () => { const state = { host: 'bitbucket.org', workspace: 'lolsWorkspace' }; const { getAllByRole } = render( - , + + + , ); expect(getAllByRole('textbox')).toHaveLength(2); @@ -57,7 +73,13 @@ describe('BitbucketRepoPicker', () => { }; const { getAllByRole } = render( - , + + + , ); expect(getAllByRole('textbox')).toHaveLength(1); @@ -67,11 +89,13 @@ describe('BitbucketRepoPicker', () => { it('calls onChange when the workspace changes', () => { const onChange = jest.fn(); const { getAllByRole } = render( - , + + + , ); const workspaceInput = getAllByRole('textbox')[0]; @@ -86,11 +110,13 @@ describe('BitbucketRepoPicker', () => { it('calls onChange when the project changes', () => { const onChange = jest.fn(); const { getAllByRole } = render( - , + + + , ); const projectInput = getAllByRole('textbox')[1]; @@ -102,11 +128,13 @@ describe('BitbucketRepoPicker', () => { it('Does not render a select if the list of allowed projects does not exist', async () => { const { getAllByRole } = render( - , + + + , ); expect(getAllByRole('textbox')).toHaveLength(2); @@ -115,12 +143,14 @@ describe('BitbucketRepoPicker', () => { it('Does not render a select if the list of allowed projects is empty', async () => { const { getAllByRole } = render( - , + + + , ); expect(getAllByRole('textbox')).toHaveLength(2); @@ -130,12 +160,14 @@ describe('BitbucketRepoPicker', () => { it('Does render a select if there is a list of allowed projects', async () => { const allowedProjects = ['project1', 'project2']; const { findByText } = render( - , + + + , ); expect(await findByText('project1')).toBeInTheDocument(); @@ -144,71 +176,17 @@ describe('BitbucketRepoPicker', () => { }); describe('autocompletion', () => { - beforeAll(() => server.listen({ onUnhandledRequest: 'error' })); - beforeEach(() => { - // BitbucketCloudClient.listWorkspaces() - server.use( - rest.get('https://api.bitbucket.org/2.0/workspaces', (_, res, ctx) => { - const response = { - values: [ - { - type: 'workspace', - slug: 'workspace1', - } as Models.Workspace, - ], - }; - return res(ctx.json(response)); - }), - ); - - // BitbucketCloudClient.listProjectsByWorkspace() - server.use( - rest.get( - 'https://api.bitbucket.org/2.0/workspaces/workspace1/projects', - (_, res, ctx) => { - const response = { - values: [ - { - type: 'project', - key: 'project1', - } as Models.Project, - ], - }; - return res(ctx.json(response)); - }, - ), - ); - - // BitbucketCloudClient.listRepositoriesByWorkspace() - server.use( - rest.get( - 'https://api.bitbucket.org/2.0/repositories/workspace1', - (_, res, ctx) => { - const response = { - values: [ - { - type: 'repository', - slug: 'repo1', - } as Models.Repository, - ], - }; - return res(ctx.json(response)); - }, - ), - ); - }); - afterAll(() => server.close()); - afterEach(() => server.resetHandlers()); - it('should populate workspaces if host is set and accessToken is provided', async () => { const onChange = jest.fn(); const { getAllByRole, getByText } = render( - , + + + , ); // Open the Autcomplete dropdown @@ -216,22 +194,28 @@ describe('BitbucketRepoPicker', () => { await userEvent.click(workspaceInput); // Verify that the available workspaces are shown - await waitFor(() => expect(getByText('workspace1')).toBeInTheDocument()); + await waitFor(() => + expect(getByText('workspaces_example')).toBeInTheDocument(), + ); // Verify that selecting an option calls onChange - await userEvent.click(getByText('workspace1')); - expect(onChange).toHaveBeenCalledWith({ workspace: 'workspace1' }); + await userEvent.click(getByText('workspaces_example')); + expect(onChange).toHaveBeenCalledWith({ + workspace: 'workspaces_example', + }); }); it('should populate projects if host and workspace are set and accessToken is provided', async () => { const onChange = jest.fn(); const { getAllByRole, getByText } = render( - , + + + , ); // Open the Autcomplete dropdown @@ -239,31 +223,37 @@ describe('BitbucketRepoPicker', () => { await userEvent.click(projectInput); // Verify that the available projects are shown - await waitFor(() => expect(getByText('project1')).toBeInTheDocument()); + await waitFor(() => + expect(getByText('projects_example')).toBeInTheDocument(), + ); // Verify that selecting an option calls onChange - await userEvent.click(getByText('project1')); - expect(onChange).toHaveBeenCalledWith({ project: 'project1' }); + await userEvent.click(getByText('projects_example')); + expect(onChange).toHaveBeenCalledWith({ project: 'projects_example' }); }); it('should populate repositories if host, workspace and project are set and accessToken is provided', async () => { const onChange = jest.fn(); render( - , + + + , ); // Verify that the available repos are updated await waitFor(() => - expect(onChange).toHaveBeenCalledWith({ availableRepos: ['repo1'] }), + expect(onChange).toHaveBeenCalledWith({ + availableRepos: ['repositories_example'], + }), ); }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 72c39fb11c..995470fbcb 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -18,10 +18,11 @@ 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 { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; import Autocomplete from '@material-ui/lab/Autocomplete'; import TextField from '@material-ui/core/TextField'; import useDebounce from 'react-use/esm/useDebounce'; +import { useApi } from '@backstage/core-plugin-api'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; /** * The underlying component that is rendered in the form for the `BitbucketRepoPicker` @@ -62,35 +63,21 @@ export const BitbucketRepoPicker = (props: { } }, [allowedOwners, host, onChange]); - const [client, setClient] = useState(); + const scaffolderApi = useApi(scaffolderApiRef); + const [availableWorkspaces, setAvailableWorkspaces] = useState([]); const [availableProjects, setAvailableProjects] = useState([]); - useEffect(() => { - if (host === 'bitbucket.org' && accessToken) { - setClient( - BitbucketCloudClient.fromConfig({ - host, - apiBaseUrl: 'https://api.bitbucket.org/2.0', - accessToken, - }), - ); - } else { - setClient(undefined); - } - }, [host, accessToken]); - // Update available workspaces when client is available useDebounce( () => { const updateAvailableWorkspaces = async () => { - if (client) { - const result: string[] = []; - - for await (const page of client.listWorkspaces().iteratePages()) { - const keys = [...page.values!].map(p => p.slug!); - result.push(...keys); - } + if (host === 'bitbucket.org' && accessToken) { + const result = await scaffolderApi.autocomplete( + accessToken, + 'bitbucketCloud', + 'workspaces', + ); setAvailableWorkspaces(result); } else { @@ -101,22 +88,20 @@ export const BitbucketRepoPicker = (props: { updateAvailableWorkspaces().catch(() => setAvailableWorkspaces([])); }, 500, - [client], + [host, accessToken], ); // Update available projects when client is available and workspace changes useDebounce( () => { const updateAvailableProjects = async () => { - if (client && workspace) { - const result: string[] = []; - - for await (const page of client - .listProjectsByWorkspace(workspace) - .iteratePages()) { - const keys = [...page.values!].map(p => p.key!); - result.push(...keys); - } + if (host === 'bitbucket.org' && accessToken && workspace) { + const result = await scaffolderApi.autocomplete( + accessToken, + 'bitbucketCloud', + 'projects', + { workspace }, + ); setAvailableProjects(result); } else { @@ -127,24 +112,20 @@ export const BitbucketRepoPicker = (props: { updateAvailableProjects().catch(() => setAvailableProjects([])); }, 500, - [client, workspace], + [host, accessToken, workspace], ); // Update available repositories when client is available and workspace or project changes useDebounce( () => { const updateAvailableRepositories = async () => { - if (client && workspace && project) { - const availableRepos: string[] = []; - - for await (const page of client - .listRepositoriesByWorkspace(workspace, { - q: `project.key="${project}"`, - }) - .iteratePages()) { - const keys = [...page.values!].map(p => p.slug!); - availableRepos.push(...keys); - } + if (host === 'bitbucket.org' && accessToken && workspace && project) { + const availableRepos = await scaffolderApi.autocomplete( + accessToken, + 'bitbucketCloud', + 'repositories', + { workspace, project }, + ); onChange({ availableRepos }); } else { @@ -157,7 +138,7 @@ export const BitbucketRepoPicker = (props: { ); }, 500, - [client, workspace, project, onChange], + [host, accessToken, workspace, project], ); return ( diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx index 269ff81271..2639e8149c 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -51,6 +51,7 @@ const scaffolderApiMock: jest.Mocked = { streamLogs: jest.fn(), listActions: jest.fn(), listTasks: jest.fn(), + autocomplete: jest.fn(), }; const catalogApiMock: jest.Mocked = { diff --git a/yarn.lock b/yarn.lock index 7f44f1559c..f81ce9dabd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7269,7 +7269,6 @@ __metadata: "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/integration-react": "workspace:^" - "@backstage/plugin-bitbucket-cloud-common": "workspace:^" "@backstage/plugin-catalog": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" From a1709aa4eeba6a175b128d0f84c872c952222ada Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 13 Jun 2024 15:30:00 +0200 Subject: [PATCH 078/860] chore: add changesets for @backstage/plugin-scaffolder-backend and @backstage/plugin-scaffolder-react; update API reports; update tests of ActionsPage Signed-off-by: Benjamin Janssens --- .changeset/slimy-ties-relate.md | 5 +++++ .changeset/tame-geese-run.md | 5 +++++ plugins/scaffolder-react/api-report.md | 7 +++++++ plugins/scaffolder/api-report.md | 7 +++++++ .../src/components/ActionsPage/ActionsPage.test.tsx | 1 + 5 files changed, 25 insertions(+) create mode 100644 .changeset/slimy-ties-relate.md create mode 100644 .changeset/tame-geese-run.md diff --git a/.changeset/slimy-ties-relate.md b/.changeset/slimy-ties-relate.md new file mode 100644 index 0000000000..d4da9972f1 --- /dev/null +++ b/.changeset/slimy-ties-relate.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Added endpoint for autocompleting provider resources (currently only supports Bitbucket) diff --git a/.changeset/tame-geese-run.md b/.changeset/tame-geese-run.md new file mode 100644 index 0000000000..785ae6c7fc --- /dev/null +++ b/.changeset/tame-geese-run.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Added method `autocomplete` to interface `ScaffolderApi` diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index 850c30ced8..cc6672a8a5 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -179,6 +179,13 @@ export type ReviewStepProps = { // @public export interface ScaffolderApi { + // (undocumented) + autocomplete( + token: string, + provider: string, + resource: string, + params?: Record, + ): Promise; cancelTask(taskId: string): Promise; // (undocumented) dryRun?(options: ScaffolderDryRunOptions): Promise; diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 5c766af890..affc69ed93 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -502,6 +502,13 @@ export class ScaffolderClient implements ScaffolderApi_2 { useLongPollingLogs?: boolean; }); // (undocumented) + autocomplete( + token: string, + provider: string, + resource: string, + params?: Record, + ): Promise; + // (undocumented) cancelTask(taskId: string): Promise; // (undocumented) dryRun( diff --git a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx index 614e3fcff0..b548bcbad4 100644 --- a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx +++ b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx @@ -33,6 +33,7 @@ const scaffolderApiMock: jest.Mocked = { streamLogs: jest.fn(), listActions: jest.fn(), listTasks: jest.fn(), + autocomplete: jest.fn(), }; const apis = TestApiRegistry.from([scaffolderApiRef, scaffolderApiMock]); From 62a9dcf8df69aba686557de3a58a873a69c6bf5e Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 13 Jun 2024 17:00:14 +0200 Subject: [PATCH 079/860] fix: use onChange instead of onInputChange to make autocomplete actually work Signed-off-by: Benjamin Janssens --- .../fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx | 5 +++++ .../fields/RepoUrlPicker/BitbucketRepoPicker.tsx | 8 ++++---- .../fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx | 3 +++ .../fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx | 5 +++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index 404fb6ddf6..10c049b3a0 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -23,6 +23,7 @@ import { ScaffolderApi, scaffolderApiRef, } from '@backstage/plugin-scaffolder-react'; +import { act } from 'react-dom/test-utils'; describe('BitbucketRepoPicker', () => { const scaffolderApiMock: Partial = { @@ -100,7 +101,9 @@ describe('BitbucketRepoPicker', () => { const workspaceInput = getAllByRole('textbox')[0]; + act(() => workspaceInput.focus()); fireEvent.change(workspaceInput, { target: { value: 'test-workspace' } }); + act(() => workspaceInput.blur()); expect(onChange).toHaveBeenCalledWith({ workspace: 'test-workspace' }); }); @@ -121,7 +124,9 @@ describe('BitbucketRepoPicker', () => { const projectInput = getAllByRole('textbox')[1]; + act(() => projectInput.focus()); fireEvent.change(projectInput, { target: { value: 'test-project' } }); + act(() => projectInput.blur()); expect(onChange).toHaveBeenCalledWith({ project: 'test-project' }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 995470fbcb..51bd1f5c67 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -163,8 +163,8 @@ export const BitbucketRepoPicker = (props: { ) : ( { - onChange({ workspace: String(newValue) }); + onChange={(_, newValue) => { + onChange({ workspace: newValue || '' }); }} options={availableWorkspaces} renderInput={params => ( @@ -198,8 +198,8 @@ export const BitbucketRepoPicker = (props: { ) : ( { - onChange({ project: String(newValue) }); + onChange={(_, newValue) => { + onChange({ project: newValue || '' }); }} options={availableProjects} renderInput={params => ( diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx index 8228f443df..efc3c94e71 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; import { render, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { act } from 'react-dom/test-utils'; describe('RepoUrlPickerRepoName', () => { it('should call onChange with the first allowed repo if there is none set already', async () => { @@ -70,7 +71,9 @@ describe('RepoUrlPickerRepoName', () => { expect(textArea).toBeVisible(); + act(() => textArea.focus()); fireEvent.change(textArea, { target: { value: 'foo' } }); + act(() => textArea.blur()); expect(onChange).toHaveBeenCalledWith('foo'); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx index cd346cf8ed..01878cb619 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx @@ -64,14 +64,15 @@ export const RepoUrlPickerRepoName = (props: { ) : ( { - onChange(String(newValue)); + onChange={(_, newValue) => { + onChange(newValue || ''); }} options={availableRepos || []} renderInput={params => ( )} freeSolo + autoSelect /> )} The name of the repository From 4d88b29995acf47b3065fa83bb89d9340f7bd806 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 13 Jun 2024 18:01:21 +0200 Subject: [PATCH 080/860] test: update tests to work with onChange Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/BitbucketRepoPicker.test.tsx | 18 ++++++++++++------ .../RepoUrlPicker/RepoUrlPicker.test.tsx | 13 ++++++++++--- .../RepoUrlPickerRepoName.test.tsx | 8 +++++--- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index 10c049b3a0..eb8c1f3a2c 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -101,9 +101,13 @@ describe('BitbucketRepoPicker', () => { const workspaceInput = getAllByRole('textbox')[0]; - act(() => workspaceInput.focus()); - fireEvent.change(workspaceInput, { target: { value: 'test-workspace' } }); - act(() => workspaceInput.blur()); + act(() => { + workspaceInput.focus(); + fireEvent.change(workspaceInput, { + target: { value: 'test-workspace' }, + }); + workspaceInput.blur(); + }); expect(onChange).toHaveBeenCalledWith({ workspace: 'test-workspace' }); }); @@ -124,9 +128,11 @@ describe('BitbucketRepoPicker', () => { const projectInput = getAllByRole('textbox')[1]; - act(() => projectInput.focus()); - fireEvent.change(projectInput, { target: { value: 'test-project' } }); - act(() => projectInput.blur()); + act(() => { + projectInput.focus(); + fireEvent.change(projectInput, { target: { value: 'test-project' } }); + projectInput.blur(); + }); expect(onChange).toHaveBeenCalledWith({ project: 'test-project' }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx index 59c09c106c..af78bc0395 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx @@ -32,7 +32,7 @@ import { useTemplateSecrets, ScaffolderRJSFField, } from '@backstage/plugin-scaffolder-react'; -import { act, fireEvent } from '@testing-library/react'; +import { act, fireEvent, waitFor } from '@testing-library/react'; describe('RepoUrlPicker', () => { const mockScaffolderApi: Partial = { @@ -98,8 +98,15 @@ describe('RepoUrlPicker', () => { const [ownerInput, repoInput] = getAllByRole('textbox'); const submitButton = getByRole('button'); - fireEvent.change(ownerInput, { target: { value: 'backstage' } }); - fireEvent.change(repoInput, { target: { value: 'repo123' } }); + act(() => { + ownerInput.focus(); + fireEvent.change(ownerInput, { target: { value: 'backstage' } }); + ownerInput.blur(); + + repoInput.focus(); + fireEvent.change(repoInput, { target: { value: 'repo123' } }); + repoInput.blur(); + }); fireEvent.click(submitButton); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx index efc3c94e71..3a32b6e175 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx @@ -71,9 +71,11 @@ describe('RepoUrlPickerRepoName', () => { expect(textArea).toBeVisible(); - act(() => textArea.focus()); - fireEvent.change(textArea, { target: { value: 'foo' } }); - act(() => textArea.blur()); + act(() => { + textArea.focus(); + fireEvent.change(textArea, { target: { value: 'foo' } }); + textArea.blur(); + }); expect(onChange).toHaveBeenCalledWith('foo'); }); From 74c95163438eac8e0a7e51d2bf04ae7f4d1cea60 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 14 Jun 2024 13:22:30 +0200 Subject: [PATCH 081/860] chore: remove unused import Signed-off-by: Benjamin Janssens --- .../src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx index af78bc0395..002652cfab 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx @@ -32,7 +32,7 @@ import { useTemplateSecrets, ScaffolderRJSFField, } from '@backstage/plugin-scaffolder-react'; -import { act, fireEvent, waitFor } from '@testing-library/react'; +import { act, fireEvent } from '@testing-library/react'; describe('RepoUrlPicker', () => { const mockScaffolderApi: Partial = { From cc183007ea0a2df88750d404df6c3cb6b41816b7 Mon Sep 17 00:00:00 2001 From: John Philip Date: Fri, 14 Jun 2024 17:49:47 -0400 Subject: [PATCH 082/860] Update techdocs.ts container image Signed-off-by: John Philip --- plugins/techdocs-node/src/stages/generate/techdocs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/techdocs-node/src/stages/generate/techdocs.ts b/plugins/techdocs-node/src/stages/generate/techdocs.ts index c5130a3f8f..a5bd0fea09 100644 --- a/plugins/techdocs-node/src/stages/generate/techdocs.ts +++ b/plugins/techdocs-node/src/stages/generate/techdocs.ts @@ -53,7 +53,7 @@ export class TechdocsGenerator implements GeneratorBase { * The default docker image (and version) used to generate content. Public * and static so that techdocs-node consumers can use the same version. */ - public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.3'; + public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.4'; private readonly logger: Logger; private readonly containerRunner?: ContainerRunner; private readonly options: GeneratorConfig; From 579afd0d3205548261334d476900721e19413561 Mon Sep 17 00:00:00 2001 From: Frank Kong Date: Fri, 14 Jun 2024 16:55:00 -0400 Subject: [PATCH 083/860] chore(auth-node): allow declarative signin resolvers to take precedence Signed-off-by: Frank Kong --- .changeset/neat-socks-cheer.md | 5 +++++ plugins/auth-node/src/oauth/createOAuthProviderFactory.ts | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 .changeset/neat-socks-cheer.md diff --git a/.changeset/neat-socks-cheer.md b/.changeset/neat-socks-cheer.md new file mode 100644 index 0000000000..5e2879b0a3 --- /dev/null +++ b/.changeset/neat-socks-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-node': patch +--- + +allow declarative sign in resolvers declared in `signInResolverFactories` to take precedence over the statically defined sign in resolvers in `signInResolver` for the `createOAuthProviderFactory`. diff --git a/plugins/auth-node/src/oauth/createOAuthProviderFactory.ts b/plugins/auth-node/src/oauth/createOAuthProviderFactory.ts index a3387b7038..fccfcb94de 100644 --- a/plugins/auth-node/src/oauth/createOAuthProviderFactory.ts +++ b/plugins/auth-node/src/oauth/createOAuthProviderFactory.ts @@ -43,11 +43,10 @@ export function createOAuthProviderFactory(options: { return ctx => { return OAuthEnvironmentHandler.mapConfig(ctx.config, envConfig => { const signInResolver = - options.signInResolver ?? readDeclarativeSignInResolver({ config: envConfig, signInResolverFactories: options.signInResolverFactories ?? {}, - }); + }) ?? options.signInResolver; return createOAuthRouteHandlers({ authenticator: options.authenticator, From a5576b2f024761f714886fed15d89e07da7724ad Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Sat, 15 Jun 2024 22:41:39 +0200 Subject: [PATCH 084/860] 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 085/860] 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 b82eaf64e2a522d7970d924ee275fbde2c9e9eda Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Sun, 16 Jun 2024 11:19:39 +0200 Subject: [PATCH 086/860] test: add tests for handleBitbucketCloudRequest Signed-off-by: Benjamin Janssens --- .../src/service/autocomplete.test.ts | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 plugins/scaffolder-backend/src/service/autocomplete.test.ts diff --git a/plugins/scaffolder-backend/src/service/autocomplete.test.ts b/plugins/scaffolder-backend/src/service/autocomplete.test.ts new file mode 100644 index 0000000000..53816f0126 --- /dev/null +++ b/plugins/scaffolder-backend/src/service/autocomplete.test.ts @@ -0,0 +1,87 @@ +/* + * 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 { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; +import { handleBitbucketCloudRequest } from './autocomplete'; +import { InputError } from '@backstage/errors'; + +describe('handleBitbucketCloudRequest', () => { + const client: Partial = { + listWorkspaces: jest.fn().mockReturnValue({ + iteratePages: jest + .fn() + .mockReturnValue([{ values: [{ slug: 'workspace1' }] }]), + }), + listProjectsByWorkspace: jest.fn().mockReturnValue({ + iteratePages: jest + .fn() + .mockReturnValue([{ values: [{ key: 'project1' }] }]), + }), + listRepositoriesByWorkspace: jest.fn().mockReturnValue({ + iteratePages: jest + .fn() + .mockReturnValue([{ values: [{ slug: 'repository1' }] }]), + }), + }; + + const fromConfig = jest + .spyOn(BitbucketCloudClient, 'fromConfig') + .mockReturnValue(client as BitbucketCloudClient); + + it('should pass the token to the client', async () => { + const accessToken = 'foo'; + await handleBitbucketCloudRequest(accessToken, 'workspaces', {}); + + expect(fromConfig).toHaveBeenCalledWith( + expect.objectContaining({ accessToken }), + ); + }); + + it('should return workspaces', async () => { + const result = await handleBitbucketCloudRequest('foo', 'workspaces', {}); + + expect(result).toEqual(['workspace1']); + }); + + it('should return projects', async () => { + const result = await handleBitbucketCloudRequest('foo', 'projects', { + workspace: 'workspace1', + }); + + expect(result).toEqual(['project1']); + }); + + it('should return repositories', async () => { + const result = await handleBitbucketCloudRequest('foo', 'repositories', { + workspace: 'workspace1', + project: 'project1', + }); + + expect(result).toEqual(['repository1']); + }); + + it('should throw an error when passing an invalid resource', async () => { + await expect( + handleBitbucketCloudRequest('token', 'invalid', {}), + ).rejects.toThrow(InputError); + }); + + it('should throw an error when there are missing parameters', async () => { + await expect( + handleBitbucketCloudRequest('token', 'projects', {}), + ).rejects.toThrow(InputError); + }); +}); From 2aa81ad13a19ddaf3a3960a976ead3ae0a83762c Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Sun, 16 Jun 2024 11:50:05 +0200 Subject: [PATCH 087/860] test: improve tests for autocomplete endpoint Signed-off-by: Benjamin Janssens --- .../src/service/router.test.ts | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 0024a57bd9..f9ff1b2a04 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -63,9 +63,7 @@ jest.mock('fs-extra', () => ({ remove: jest.fn(), })); -jest.mock('./autocomplete', () => ({ - handleBitbucketCloudRequest: jest.fn(), -})); +jest.mock('./autocomplete'); function createDatabase(): PluginDatabaseManager { return DatabaseManager.fromConfig( @@ -1469,18 +1467,25 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ describe('GET /v2/autocomplete/:provider/:resource', () => { it('should handle requests for provider bitbucketCloud', async () => { + jest + .mocked(handleBitbucketCloudRequest) + .mockResolvedValue(['resource1']); + const bbToken = 'foo'; const resource = 'bar'; - await request(app) - .get(`/v2/autocomplete/bitbucketCloud/${resource}?token=${bbToken}`) - .send(); + const response = await request(app) + .get(`/v2/autocomplete/bitbucketCloud/${resource}`) + .query({ token: bbToken, workspace: 'workspace1' }); - expect(jest.mocked(handleBitbucketCloudRequest)).toHaveBeenCalledWith( + expect(handleBitbucketCloudRequest).toHaveBeenCalledWith( bbToken, resource, - {}, + { workspace: 'workspace1' }, ); + + expect(response.status).toEqual(200); + expect(response.body).toEqual(['resource1']); }); }); }); From 025f23f01343b66f85e439fc684546f9abf2cc2f Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Sun, 16 Jun 2024 12:02:23 +0200 Subject: [PATCH 088/860] test: clean up tests Signed-off-by: Benjamin Janssens --- .../fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx | 3 +++ .../fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index eb8c1f3a2c..18ce8d2c76 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -189,6 +189,7 @@ describe('BitbucketRepoPicker', () => { describe('autocompletion', () => { it('should populate workspaces if host is set and accessToken is provided', async () => { const onChange = jest.fn(); + const { getAllByRole, getByText } = render( { it('should populate projects if host and workspace are set and accessToken is provided', async () => { const onChange = jest.fn(); + const { getAllByRole, getByText } = render( { it('should populate repositories if host, workspace and project are set and accessToken is provided', async () => { const onChange = jest.fn(); + render( { } // Verify that selecting an option calls onChange - await userEvent.click(getByText('foo')); - expect(onChange).toHaveBeenCalledWith('foo'); + await userEvent.click(getByText(availableRepos[0])); + expect(onChange).toHaveBeenCalledWith(availableRepos[0]); }); }); From 66d852407e16bab4cdf3fff171e9f50171d02acc Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Sun, 16 Jun 2024 14:08:57 +0200 Subject: [PATCH 089/860] 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 090/860] 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 091/860] 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 092/860] 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 093/860] 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 094/860] 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 095/860] 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 096/860] 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 097/860] 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 098/860] 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 099/860] 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 09:36:27 +0200 Subject: [PATCH 100/860] Update .changeset/fair-rockets-leave.md Signed-off-by: Kacper Nowacki --- .changeset/fair-rockets-leave.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/fair-rockets-leave.md b/.changeset/fair-rockets-leave.md index 41cf28fc9e..20f2e97552 100644 --- a/.changeset/fair-rockets-leave.md +++ b/.changeset/fair-rockets-leave.md @@ -2,5 +2,5 @@ '@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch --- -Instead of using hardcoded targetBranch we are fetching 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`. +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`. From 847d1743a3db371116d26b96d55e79d305a8763b Mon Sep 17 00:00:00 2001 From: mario ma Date: Tue, 18 Jun 2024 16:27:59 +0800 Subject: [PATCH 101/860] 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 102/860] 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 103/860] 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 104/860] 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 105/860] 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 106/860] 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 107/860] 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 108/860] 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 109/860] 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 110/860] 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 62d1fe301cc652b399170acd91a7c1edeb6c8fdb Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Tue, 18 Jun 2024 01:25:03 -0400 Subject: [PATCH 111/860] Fix user entity not being fetched for scaffolder dry runner Signed-off-by: Stephen Glass --- .changeset/young-fishes-lie.md | 5 ++++ .../src/scaffolder/dryrun/createDryRunner.ts | 5 ++++ .../src/service/router.test.ts | 28 +++++++++++++++++++ .../scaffolder-backend/src/service/router.ts | 12 ++++++++ 4 files changed, 50 insertions(+) create mode 100644 .changeset/young-fishes-lie.md diff --git a/.changeset/young-fishes-lie.md b/.changeset/young-fishes-lie.md new file mode 100644 index 0000000000..769d046375 --- /dev/null +++ b/.changeset/young-fishes-lie.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Fix user entity not being fetched for scaffolder dry runner diff --git a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts index 6b8caf5a3d..c993e0d46d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts @@ -38,12 +38,17 @@ import { BackstageCredentials, resolveSafeChildPath, } from '@backstage/backend-plugin-api'; +import type { UserEntity } from '@backstage/catalog-model'; interface DryRunInput { spec: TaskSpec; secrets?: TaskSecrets; directoryContents: SerializedFile[]; credentials: BackstageCredentials; + user?: { + entity?: UserEntity; + ref?: string; + }; } interface DryRunResult { diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 8ba26c68a4..c776f563d7 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -691,6 +691,34 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(subscriber!.closed).toBe(true); }); }); + + describe('POST /v2/dry-run', () => { + it('should get user entity', async () => { + const mockToken = mockCredentials.user.token(); + const mockTemplate = getMockTemplate(); + + const catalogSpy = jest.spyOn(catalogClient, 'getEntityByRef'); + + await request(app) + .post('/v2/dry-run') + .set('Authorization', `Bearer ${mockToken}`) + .send({ + template: mockTemplate, + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + directoryContents: [], + }); + + expect(catalogSpy).toHaveBeenCalledTimes(1); + + expect(catalogSpy).toHaveBeenCalledWith( + 'user:default/mock', + expect.anything(), + ); + }); + }); }); describe('providing an identity api', () => { diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 384b9f5340..84cdac0c3f 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -730,6 +730,14 @@ export async function createRouter( targetPluginId: 'catalog', }); + const userEntityRef = auth.isPrincipal(credentials, 'user') + ? credentials.principal.userEntityRef + : undefined; + + const userEntity = userEntityRef + ? await catalogClient.getEntityByRef(userEntityRef, { token }) + : undefined; + for (const parameters of [template.spec.parameters ?? []].flat()) { const result = validate(body.values, parameters); if (!result.valid) { @@ -750,6 +758,10 @@ export async function createRouter( steps, output: template.spec.output ?? {}, parameters: body.values as JsonObject, + user: { + entity: userEntity as UserEntity, + ref: userEntityRef, + }, }, directoryContents: (body.directoryContents ?? []).map(file => ({ path: file.path, From a82cbab3c4a507d74e95ba5d07b1d27fce1f2470 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 19 Jun 2024 10:25:42 +0200 Subject: [PATCH 112/860] chore: starting to refactor a little bit] Signed-off-by: blam --- .../src/ScaffolderPlugin.ts | 8 ++++++ .../src/service/autocomplete.ts | 2 +- plugins/scaffolder-node/src/alpha.ts | 28 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index a8213cf585..9fc4b2537a 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -29,6 +29,7 @@ import { } from '@backstage/plugin-scaffolder-node'; import { scaffolderActionsExtensionPoint, + scaffolderAutocompleteExtensionPoint, scaffolderTaskBrokerExtensionPoint, scaffolderTemplatingExtensionPoint, } from '@backstage/plugin-scaffolder-node/alpha'; @@ -82,6 +83,13 @@ export const scaffolderPlugin = createBackendPlugin({ }, }); + const autocompleteResolers = []; + env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, { + addAutocompleteProvider(provider) { + autocompleteResolers.push(provider); + }, + }); + env.registerInit({ deps: { logger: coreServices.logger, diff --git a/plugins/scaffolder-backend/src/service/autocomplete.ts b/plugins/scaffolder-backend/src/service/autocomplete.ts index 034a201450..131305d53e 100644 --- a/plugins/scaffolder-backend/src/service/autocomplete.ts +++ b/plugins/scaffolder-backend/src/service/autocomplete.ts @@ -17,7 +17,7 @@ import { InputError } from '@backstage/errors'; import { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; -export async function handleBitbucketCloudRequest( +export async function handleAutocompleteRequest( token: string, resource: string, parameters: Record, diff --git a/plugins/scaffolder-node/src/alpha.ts b/plugins/scaffolder-node/src/alpha.ts index b85da5b590..3644d48b7c 100644 --- a/plugins/scaffolder-node/src/alpha.ts +++ b/plugins/scaffolder-node/src/alpha.ts @@ -79,3 +79,31 @@ export const scaffolderTemplatingExtensionPoint = createExtensionPoint({ id: 'scaffolder.templating', }); + +/** + * Extension point for adding autocomplete handler providers + * @alpha + */ +export interface ScaffolderAutocompleteExtensionPoint { + addAutocompleteProvider( + provider: ({ + type, + token, + query, + }: { + type: string; + token: string; + query: Record; + }) => Promise<{ results: { title: string }[] }>, + ): void; +} + +/** + * Extension point for adding template filters and globals. + * + * @alpha + */ +export const scaffolderAutocompleteExtensionPoint = + createExtensionPoint({ + id: 'scaffolder.autocomplete', + }); From 3583ce550c16a2c17034e632c6b0d996ddd1df9f Mon Sep 17 00:00:00 2001 From: Mikko Korhonen Date: Wed, 19 Jun 2024 11:29:39 +0300 Subject: [PATCH 113/860] feat(scaffolder): use virtualization with MultiEntityPicker Signed-off-by: Mikko Korhonen --- .changeset/heavy-moose-pull.md | 5 +++ plugins/scaffolder/package.json | 2 ++ .../MultiEntityPicker/MultiEntityPicker.tsx | 34 +++++++++++++++++++ yarn.lock | 6 ++-- 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .changeset/heavy-moose-pull.md diff --git a/.changeset/heavy-moose-pull.md b/.changeset/heavy-moose-pull.md new file mode 100644 index 0000000000..7ba7b1aa39 --- /dev/null +++ b/.changeset/heavy-moose-pull.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Use virtualization with MultiEntityPicker. Fixes performance issues with large data sets. diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index f2c96eee58..50cbda8e31 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -97,6 +97,7 @@ "luxon": "^3.0.0", "qs": "^6.9.4", "react-use": "^17.2.4", + "react-window": "^1.8.10", "yaml": "^2.0.0", "zen-observable": "^0.10.0", "zod": "^3.22.4", @@ -115,6 +116,7 @@ "@testing-library/user-event": "^14.0.0", "@types/humanize-duration": "^3.18.1", "@types/json-schema": "^7.0.9", + "@types/react-window": "^1.8.8", "msw": "^1.0.0", "swr": "^2.0.0" }, diff --git a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx index 4ea26b4414..84a050622a 100644 --- a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx @@ -35,6 +35,7 @@ import Autocomplete, { AutocompleteChangeReason, } from '@material-ui/lab/Autocomplete'; import React, { useCallback, useEffect } from 'react'; +import { FixedSizeList, ListChildComponentProps } from 'react-window'; import useAsync from 'react-use/esm/useAsync'; import { FieldValidation } from '@rjsf/utils'; import { @@ -46,6 +47,38 @@ import { export { MultiEntityPickerSchema } from './schema'; +const renderRow = (props: ListChildComponentProps) => { + const { data, index, style } = props; + return React.cloneElement(data[index], { style }); +}; + +const ListboxComponent = React.forwardRef< + HTMLDivElement, + { children?: React.ReactNode } +>((props, ref) => { + const itemData = React.Children.toArray(props.children); + const itemCount = itemData.length; + + const itemSize = 36; + + const itemsToShow = Math.min(10, itemCount); + const height = Math.max(itemSize, itemsToShow * itemSize - 0.5 * itemSize); + + return ( +
    + + {renderRow} + +
    + ); +}); + /** * The underlying component that is rendered in the form for the `MultiEntityPicker` * field extension. @@ -177,6 +210,7 @@ export const MultiEntityPicker = (props: MultiEntityPickerProps) => { }} /> )} + ListboxComponent={ListboxComponent} /> ); diff --git a/yarn.lock b/yarn.lock index a0a385ca66..7cf1726496 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7138,6 +7138,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-window": ^1.8.8 "@uiw/react-codemirror": ^4.9.3 classnames: ^2.2.6 git-url-parse: ^14.0.0 @@ -7150,6 +7151,7 @@ __metadata: msw: ^1.0.0 qs: ^6.9.4 react-use: ^17.2.4 + react-window: ^1.8.10 swr: ^2.0.0 yaml: ^2.0.0 zen-observable: ^0.10.0 @@ -18077,7 +18079,7 @@ __metadata: languageName: node linkType: hard -"@types/react-window@npm:^1.8.5": +"@types/react-window@npm:^1.8.5, @types/react-window@npm:^1.8.8": version: 1.8.8 resolution: "@types/react-window@npm:1.8.8" dependencies: @@ -38305,7 +38307,7 @@ __metadata: languageName: node linkType: hard -"react-window@npm:^1.8.6": +"react-window@npm:^1.8.10, react-window@npm:^1.8.6": version: 1.8.10 resolution: "react-window@npm:1.8.10" dependencies: From 083eaf98b3413b814d1c03702627b0c30f052179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 18 Jun 2024 17:28:22 +0200 Subject: [PATCH 114/860] fix iso duration parsing in schedules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/curvy-teachers-smell.md | 8 +++ .../scheduler/lib/PluginTaskSchedulerImpl.ts | 2 +- .../definitions/SchedulerService.test.ts | 5 +- .../services/definitions/SchedulerService.ts | 6 +- ...adTaskScheduleDefinitionFromConfig.test.ts | 5 +- .../readTaskScheduleDefinitionFromConfig.ts | 4 +- .../catalogModuleAwsS3EntityProvider.test.ts | 5 +- .../src/providers/config.test.ts | 3 +- ...logModuleAzureDevOpsEntityProvider.test.ts | 5 +- .../src/providers/config.test.ts | 3 +- ...ModuleBitbucketCloudEntityProvider.test.ts | 5 +- ...BitbucketCloudEntityProviderConfig.test.ts | 3 +- ...oduleBitbucketServerEntityProvider.test.ts | 5 +- ...itbucketServerEntityProviderConfig.test.ts | 3 +- .../catalogModuleGerritEntityProvider.test.ts | 5 +- .../src/providers/config.test.ts | 3 +- .../src/module.test.ts | 5 +- .../src/module/githubCatalogModule.test.ts | 5 +- .../GithubEntityProviderConfig.test.ts | 3 +- ...leGitlabOrgDiscoveryEntityProvider.test.ts | 5 +- ...oduleGitlabDiscoveryEntityProvider.test.ts | 5 +- .../src/providers/config.test.ts | 3 +- .../catalog-backend-module-ldap/api-report.md | 14 ++-- .../src/ldap/config.test.ts | 69 +++++++++++++++++++ .../src/ldap/config.ts | 12 ++-- .../src/processors/LdapOrgEntityProvider.ts | 19 ++--- .../src/microsoftGraph/config.test.ts | 3 +- ...uleMicrosoftGraphOrgEntityProvider.test.ts | 5 +- .../PuppetDbEntityProviderConfig.test.ts | 7 +- 29 files changed, 142 insertions(+), 83 deletions(-) create mode 100644 .changeset/curvy-teachers-smell.md diff --git a/.changeset/curvy-teachers-smell.md b/.changeset/curvy-teachers-smell.md new file mode 100644 index 0000000000..3f032f2177 --- /dev/null +++ b/.changeset/curvy-teachers-smell.md @@ -0,0 +1,8 @@ +--- +'@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/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts index 62b36e024c..40aa9d521c 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts @@ -152,7 +152,7 @@ export class PluginTaskSchedulerImpl implements SchedulerService { export function parseDuration( frequency: SchedulerServiceTaskScheduleDefinition['frequency'], ): string { - if ('cron' in frequency) { + if (typeof frequency === 'object' && 'cron' in frequency) { return frequency.cron; } diff --git a/packages/backend-plugin-api/src/services/definitions/SchedulerService.test.ts b/packages/backend-plugin-api/src/services/definitions/SchedulerService.test.ts index 7b20487af4..875e24786f 100644 --- a/packages/backend-plugin-api/src/services/definitions/SchedulerService.test.ts +++ b/packages/backend-plugin-api/src/services/definitions/SchedulerService.test.ts @@ -16,7 +16,6 @@ import { ConfigReader } from '@backstage/config'; import { HumanDuration } from '@backstage/types'; -import { Duration } from 'luxon'; import { readSchedulerServiceTaskScheduleDefinitionFromConfig } from './SchedulerService'; describe('readSchedulerServiceTaskScheduleDefinitionFromConfig', () => { @@ -35,7 +34,7 @@ describe('readSchedulerServiceTaskScheduleDefinitionFromConfig', () => { const result = readSchedulerServiceTaskScheduleDefinitionFromConfig(config); expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *'); - expect(result.timeout).toEqual(Duration.fromISO('PT3M')); + expect(result.timeout).toEqual({ minutes: 3 }); expect((result.initialDelay as HumanDuration).minutes).toEqual(20); expect(result.scope).toBe('global'); }); @@ -51,7 +50,7 @@ describe('readSchedulerServiceTaskScheduleDefinitionFromConfig', () => { const result = readSchedulerServiceTaskScheduleDefinitionFromConfig(config); expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *'); - expect(result.timeout).toEqual(Duration.fromISO('PT3M')); + expect(result.timeout).toEqual({ minutes: 3 }); expect(result.initialDelay).toBeUndefined(); expect(result.scope).toBeUndefined(); }); diff --git a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts index 91edf27ad6..a7ec79a336 100644 --- a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts +++ b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts @@ -348,14 +348,14 @@ export interface SchedulerService { getScheduledTasks(): Promise; } -function readDuration(config: Config, key: string): Duration | HumanDuration { +function readDuration(config: Config, key: string): HumanDuration { if (typeof config.get(key) === 'string') { const value = config.getString(key); const duration = Duration.fromISO(value); if (!duration.isValid) { throw new Error(`Invalid duration: ${value}`); } - return duration; + return duration.toObject(); } return readDurationFromConfig(config, { key }); @@ -364,7 +364,7 @@ function readDuration(config: Config, key: string): Duration | HumanDuration { function readCronOrDuration( config: Config, key: string, -): { cron: string } | Duration | HumanDuration { +): { cron: string } | HumanDuration { const value = config.get(key); if (typeof value === 'object' && (value as { cron?: string }).cron) { return value as { cron: string }; diff --git a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.test.ts b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.test.ts index c52d59b016..adeb134611 100644 --- a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.test.ts +++ b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.test.ts @@ -16,7 +16,6 @@ import { ConfigReader } from '@backstage/config'; import { HumanDuration } from '@backstage/types'; -import { Duration } from 'luxon'; import { readTaskScheduleDefinitionFromConfig } from './readTaskScheduleDefinitionFromConfig'; describe('readTaskScheduleDefinitionFromConfig', () => { @@ -35,7 +34,7 @@ describe('readTaskScheduleDefinitionFromConfig', () => { const result = readTaskScheduleDefinitionFromConfig(config); expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *'); - expect(result.timeout).toEqual(Duration.fromISO('PT3M')); + expect(result.timeout).toEqual({ minutes: 3 }); expect((result.initialDelay as HumanDuration).minutes).toEqual(20); expect(result.scope).toBe('global'); }); @@ -51,7 +50,7 @@ describe('readTaskScheduleDefinitionFromConfig', () => { const result = readTaskScheduleDefinitionFromConfig(config); expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *'); - expect(result.timeout).toEqual(Duration.fromISO('PT3M')); + expect(result.timeout).toEqual({ minutes: 3 }); expect(result.initialDelay).toBeUndefined(); expect(result.scope).toBeUndefined(); }); diff --git a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts index 5a173f246b..e94d06d5c3 100644 --- a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts +++ b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts @@ -19,14 +19,14 @@ import { HumanDuration } from '@backstage/types'; import { TaskScheduleDefinition } from './types'; import { Duration } from 'luxon'; -function readDuration(config: Config, key: string): Duration | HumanDuration { +function readDuration(config: Config, key: string): HumanDuration { if (typeof config.get(key) === 'string') { const value = config.getString(key); const duration = Duration.fromISO(value); if (!duration.isValid) { throw new Error(`Invalid duration: ${value}`); } - return duration; + return duration.toObject(); } return readDurationFromConfig(config, { key }); diff --git a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts index 4addd1cb45..9165eb4322 100644 --- a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts +++ b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts @@ -17,7 +17,6 @@ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { Duration } from 'luxon'; import { catalogModuleAwsS3EntityProvider } from './catalogModuleAwsS3EntityProvider'; import { AwsS3EntityProvider } from '../providers'; @@ -62,8 +61,8 @@ describe('catalogModuleAwsS3EntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(addedProviders?.pop()?.getProviderName()).toEqual( 'awsS3-provider:default', diff --git a/plugins/catalog-backend-module-aws/src/providers/config.test.ts b/plugins/catalog-backend-module-aws/src/providers/config.test.ts index fb2f3c0790..4c7ec9a964 100644 --- a/plugins/catalog-backend-module-aws/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-aws/src/providers/config.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readAwsS3Configs } from './config'; describe('readAwsS3Configs', () => { @@ -92,7 +91,7 @@ describe('readAwsS3Configs', () => { id: 'provider4', schedule: { ...provider4.schedule, - frequency: Duration.fromISO(provider4.schedule.frequency), + frequency: { minutes: 30 }, }, }); }); diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts index 2c674a8061..e406c61e07 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts @@ -17,7 +17,6 @@ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { Duration } from 'luxon'; import { catalogModuleAzureDevOpsEntityProvider } from './catalogModuleAzureDevOpsEntityProvider'; import { AzureDevOpsEntityProvider } from '../providers'; @@ -66,8 +65,8 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(addedProviders?.pop()?.getProviderName()).toEqual( 'AzureDevOpsEntityProvider:test', diff --git a/plugins/catalog-backend-module-azure/src/providers/config.test.ts b/plugins/catalog-backend-module-azure/src/providers/config.test.ts index 02dbaab90e..5d5ae930c1 100644 --- a/plugins/catalog-backend-module-azure/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-azure/src/providers/config.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readAzureDevOpsConfigs } from './config'; describe('readAzureDevOpsConfigs', () => { @@ -95,7 +94,7 @@ describe('readAzureDevOpsConfigs', () => { id: 'provider4', schedule: { ...provider4.schedule, - frequency: Duration.fromISO(provider4.schedule.frequency), + frequency: { minutes: 30 }, }, }); expect(actual[4]).toEqual({ diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts index db53b0b41b..bcf13e786d 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts @@ -21,7 +21,6 @@ import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { TestEventsService } from '@backstage/plugin-events-backend-test-utils'; import { eventsServiceRef } from '@backstage/plugin-events-node'; -import { Duration } from 'luxon'; import { catalogModuleBitbucketCloudEntityProvider } from './catalogModuleBitbucketCloudEntityProvider'; import { BitbucketCloudEntityProvider } from '../providers/BitbucketCloudEntityProvider'; @@ -78,8 +77,8 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(runner).not.toHaveBeenCalled(); const provider = addedProviders!.pop()!; diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProviderConfig.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProviderConfig.test.ts index 5a2cc99437..7f13616586 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProviderConfig.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProviderConfig.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readProviderConfigs } from './BitbucketCloudEntityProviderConfig'; describe('readProviderConfigs', () => { @@ -130,7 +129,7 @@ describe('readProviderConfigs', () => { repoSlug: undefined, }, schedule: { - frequency: Duration.fromISO('PT30M'), + frequency: { minutes: 30 }, timeout: { minutes: 3, }, diff --git a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts index 56b44b29f5..5335b04e2d 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts @@ -18,7 +18,6 @@ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { catalogModuleBitbucketServerEntityProvider } from './catalogModuleBitbucketServerEntityProvider'; -import { Duration } from 'luxon'; import { BitbucketServerEntityProvider } from '../providers'; describe('catalogModuleBitbucketServerEntityProvider', () => { @@ -70,8 +69,8 @@ describe('catalogModuleBitbucketServerEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(addedProviders?.pop()?.getProviderName()).toEqual( 'bitbucketServer-provider:default', diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts index 9e8aca5dd9..755fa4b58a 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readProviderConfigs } from './BitbucketServerEntityProviderConfig'; describe('readProviderConfigs', () => { @@ -111,7 +110,7 @@ describe('readProviderConfigs', () => { skipArchivedRepos: undefined, }, schedule: { - frequency: Duration.fromISO('PT30M'), + frequency: { minutes: 30 }, timeout: { minutes: 3, }, diff --git a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts index 66f0cbab2c..dc40e0525d 100644 --- a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts @@ -17,7 +17,6 @@ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { Duration } from 'luxon'; import { catalogModuleGerritEntityProvider } from './catalogModuleGerritEntityProvider'; import { GerritEntityProvider } from '../providers/GerritEntityProvider'; @@ -76,8 +75,8 @@ describe('catalogModuleGerritEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(addedProviders?.pop()?.getProviderName()).toEqual( 'gerrit-provider:test', diff --git a/plugins/catalog-backend-module-gerrit/src/providers/config.test.ts b/plugins/catalog-backend-module-gerrit/src/providers/config.test.ts index ecf68d9f3c..85ab3383f0 100644 --- a/plugins/catalog-backend-module-gerrit/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/providers/config.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readGerritConfigs } from './config'; describe('readGerritConfigs', () => { @@ -63,7 +62,7 @@ describe('readGerritConfigs', () => { id: 'active-g3', schedule: { ...provider3.schedule, - frequency: Duration.fromISO(provider3.schedule.frequency), + frequency: { minutes: 30 }, }, }); }); diff --git a/plugins/catalog-backend-module-github-org/src/module.test.ts b/plugins/catalog-backend-module-github-org/src/module.test.ts index 6e03d8d9cc..76ab4d1fbc 100644 --- a/plugins/catalog-backend-module-github-org/src/module.test.ts +++ b/plugins/catalog-backend-module-github-org/src/module.test.ts @@ -18,7 +18,6 @@ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { Duration } from 'luxon'; import { catalogModuleGithubOrgEntityProvider } from './module'; describe('catalogModuleGithubOrgEntityProvider', () => { @@ -66,8 +65,8 @@ describe('catalogModuleGithubOrgEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(addedProviders![0].getProviderName()).toEqual( 'GithubMultiOrgEntityProvider:default', diff --git a/plugins/catalog-backend-module-github/src/module/githubCatalogModule.test.ts b/plugins/catalog-backend-module-github/src/module/githubCatalogModule.test.ts index 59f8b41a6d..018d339de8 100644 --- a/plugins/catalog-backend-module-github/src/module/githubCatalogModule.test.ts +++ b/plugins/catalog-backend-module-github/src/module/githubCatalogModule.test.ts @@ -21,7 +21,6 @@ import { catalogAnalysisExtensionPoint, catalogProcessingExtensionPoint, } from '@backstage/plugin-catalog-node/alpha'; -import { Duration } from 'luxon'; import { githubCatalogModule } from './githubCatalogModule'; import { GithubLocationAnalyzer } from '../analyzers/GithubLocationAnalyzer'; @@ -75,8 +74,8 @@ describe('githubCatalogModule', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(addedProviders?.pop()?.getProviderName()).toEqual( 'github-provider:default', diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts index c83bfe5db1..296cbc12df 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readProviderConfigs } from './GithubEntityProviderConfig'; describe('readProviderConfigs', () => { @@ -270,7 +269,7 @@ describe('readProviderConfigs', () => { visibility: undefined, }, schedule: { - frequency: Duration.fromISO('PT30M'), + frequency: { minutes: 30 }, timeout: { minutes: 3, }, diff --git a/plugins/catalog-backend-module-gitlab-org/src/catalogModuleGitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab-org/src/catalogModuleGitlabOrgDiscoveryEntityProvider.test.ts index 1078936950..5fbc321cc2 100644 --- a/plugins/catalog-backend-module-gitlab-org/src/catalogModuleGitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab-org/src/catalogModuleGitlabOrgDiscoveryEntityProvider.test.ts @@ -22,7 +22,6 @@ import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { TestEventsService } from '@backstage/plugin-events-backend-test-utils'; import { eventsServiceRef } from '@backstage/plugin-events-node'; -import { Duration } from 'luxon'; import { catalogModuleGitlabOrgDiscoveryEntityProvider } from './catalogModuleGitlabOrgDiscoveryEntityProvider'; describe('catalogModuleGitlabOrgDiscoveryEntityProvider', () => { @@ -90,8 +89,8 @@ describe('catalogModuleGitlabOrgDiscoveryEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(runner).not.toHaveBeenCalled(); diff --git a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts index e4cff56bbd..636405220b 100644 --- a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts @@ -21,7 +21,6 @@ import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { TestEventsService } from '@backstage/plugin-events-backend-test-utils'; import { eventsServiceRef } from '@backstage/plugin-events-node'; -import { Duration } from 'luxon'; import { GitlabDiscoveryEntityProvider } from '../providers'; import { catalogModuleGitlabDiscoveryEntityProvider } from './catalogModuleGitlabDiscoveryEntityProvider'; @@ -89,8 +88,8 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(runner).not.toHaveBeenCalled(); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts index 09b42e6475..a5c3ab2b28 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readGitlabConfigs } from './config'; describe('config', () => { @@ -179,7 +178,7 @@ describe('config', () => { allowInherited: false, skipForkedRepos: false, schedule: { - frequency: Duration.fromISO('PT30M'), + frequency: { minutes: 30 }, timeout: { minutes: 3, }, diff --git a/plugins/catalog-backend-module-ldap/api-report.md b/plugins/catalog-backend-module-ldap/api-report.md index 84de581387..de245b8cd6 100644 --- a/plugins/catalog-backend-module-ldap/api-report.md +++ b/plugins/catalog-backend-module-ldap/api-report.md @@ -16,11 +16,11 @@ import { GroupTransformer as GroupTransformer_2 } from '@backstage/plugin-catalo import { JsonValue } from '@backstage/types'; import { LocationSpec } from '@backstage/plugin-catalog-common'; import { LoggerService } from '@backstage/backend-plugin-api'; -import { PluginTaskScheduler } from '@backstage/backend-tasks'; +import { SchedulerService } from '@backstage/backend-plugin-api'; +import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api'; +import { SchedulerServiceTaskScheduleDefinition } from '@backstage/backend-plugin-api'; import { SearchEntry } from 'ldapjs'; import { SearchOptions } from 'ldapjs'; -import { TaskRunner } from '@backstage/backend-tasks'; -import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { UserEntity } from '@backstage/catalog-model'; import { UserTransformer as UserTransformer_2 } from '@backstage/plugin-catalog-backend-module-ldap'; @@ -135,7 +135,7 @@ export interface LdapOrgEntityProviderLegacyOptions { groupTransformer?: GroupTransformer; id: string; logger: LoggerService; - schedule: 'manual' | TaskRunner; + schedule: 'manual' | SchedulerServiceTaskRunner; target: string; userTransformer?: UserTransformer; } @@ -145,8 +145,8 @@ export type LdapOrgEntityProviderOptions = | LdapOrgEntityProviderLegacyOptions | { logger: LoggerService; - schedule?: 'manual' | TaskRunner; - scheduler?: PluginTaskScheduler; + schedule?: 'manual' | SchedulerServiceTaskRunner; + scheduler?: SchedulerService; userTransformer?: UserTransformer | Record; groupTransformer?: GroupTransformer | Record; }; @@ -199,7 +199,7 @@ export type LdapProviderConfig = { bind?: BindConfig; users: UserConfig; groups: GroupConfig; - schedule?: TaskScheduleDefinition; + schedule?: SchedulerServiceTaskScheduleDefinition; }; // @public 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..4edfaeebea 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts @@ -79,6 +79,75 @@ describe('readLdapConfig', () => { expect(actual).toEqual(expected); }); + it('reads schedules well', () => { + const config = { + catalog: { + providers: { + ldapOrg: { + default: { + schedule: { + frequency: 'PT3M', // should work for ISO durations + timeout: { minutes: 1 }, + }, + target: 'target', + users: { + dn: 'udn', + }, + groups: { + dn: 'gdn', + }, + }, + }, + }, + }, + }; + const actual = readProviderConfigs(new ConfigReader(config)); + const expected = [ + { + id: 'default', + target: 'target', + bind: undefined, + schedule: { + frequency: { minutes: 3 }, + timeout: { minutes: 1 }, + }, + users: { + dn: 'udn', + options: { + scope: 'one', + attributes: ['*', '+'], + }, + 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', + }, + }, + }, + ]; + expect(actual).toEqual(expected); + }); + it('reads all the values', () => { const config = { catalog: { diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts index 2bd21fd166..7c4795fc46 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -15,9 +15,9 @@ */ import { - readTaskScheduleDefinitionFromConfig, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; + SchedulerServiceTaskScheduleDefinition, + readSchedulerServiceTaskScheduleDefinitionFromConfig, +} from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; import { JsonValue } from '@backstage/types'; import { SearchOptions } from 'ldapjs'; @@ -46,7 +46,7 @@ export type LdapProviderConfig = { // The settings that govern the reading and interpretation of groups groups: GroupConfig; // Schedule configuration for refresh tasks. - schedule?: TaskScheduleDefinition; + schedule?: SchedulerServiceTaskScheduleDefinition; }; /** @@ -380,7 +380,9 @@ export function readProviderConfigs(config: Config): LdapProviderConfig[] { const c = providersConfig.getConfig(id); const schedule = c.has('schedule') - ? readTaskScheduleDefinitionFromConfig(c.getConfig('schedule')) + ? readSchedulerServiceTaskScheduleDefinitionFromConfig( + c.getConfig('schedule'), + ) : undefined; const newConfig = { diff --git a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts index fb8f27d685..0e5fae55bb 100644 --- a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { PluginTaskScheduler, TaskRunner } from '@backstage/backend-tasks'; import { ANNOTATION_LOCATION, ANNOTATION_ORIGIN_LOCATION, @@ -35,7 +34,11 @@ import { readLdapOrg, UserTransformer, } from '../ldap'; -import { LoggerService } from '@backstage/backend-plugin-api'; +import { + LoggerService, + SchedulerService, + SchedulerServiceTaskRunner, +} from '@backstage/backend-plugin-api'; import { readLdapLegacyConfig, readProviderConfigs } from '../ldap'; /** @@ -60,16 +63,16 @@ export type LdapOrgEntityProviderOptions = * manually at some interval. * * But more commonly you will pass in the result of - * {@link @backstage/backend-tasks#PluginTaskScheduler.createScheduledTaskRunner} + * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner} * to enable automatic scheduling of tasks. */ - schedule?: 'manual' | TaskRunner; + schedule?: 'manual' | SchedulerServiceTaskRunner; /** * Scheduler used to schedule refreshes based on * the schedule config. */ - scheduler?: PluginTaskScheduler; + scheduler?: SchedulerService; /** * The function that transforms a user entry in msgraph to an entity. @@ -122,10 +125,10 @@ export interface LdapOrgEntityProviderLegacyOptions { * manually at some interval. * * But more commonly you will pass in the result of - * {@link @backstage/backend-tasks#PluginTaskScheduler.createScheduledTaskRunner} + * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner} * to enable automatic scheduling of tasks. */ - schedule: 'manual' | TaskRunner; + schedule: 'manual' | SchedulerServiceTaskRunner; /** * The function that transforms a user entry in LDAP to an entity. @@ -311,7 +314,7 @@ export class LdapOrgEntityProvider implements EntityProvider { markCommitComplete(); } - private schedule(taskRunner: TaskRunner) { + private schedule(taskRunner: SchedulerServiceTaskRunner) { this.scheduleFn = async () => { const id = `${this.getProviderName()}:refresh`; await taskRunner.run({ 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..c0e9f61f29 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts @@ -15,7 +15,6 @@ */ import { ConfigReader } from '@backstage/config'; -import { Duration } from 'luxon'; import { readMicrosoftGraphConfig, readProviderConfigs } from './config'; describe('readMicrosoftGraphConfig', () => { @@ -204,7 +203,7 @@ describe('readProviderConfigs', () => { groupSelect: ['id', 'displayName', 'description'], groupFilter: 'securityEnabled eq false', schedule: { - frequency: Duration.fromISO('PT30M'), + frequency: { minutes: 30 }, timeout: { minutes: 3, }, diff --git a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts index 5742fbbc6c..2a3e66a9b3 100644 --- a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts @@ -17,7 +17,6 @@ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { Duration } from 'luxon'; import { catalogModuleMicrosoftGraphOrgEntityProvider } from './catalogModuleMicrosoftGraphOrgEntityProvider'; import { MicrosoftGraphOrgEntityProvider } from '../processors'; @@ -67,8 +66,8 @@ describe('catalogModuleMicrosoftGraphOrgEntityProvider', () => { ], }); - expect(usedSchedule?.frequency).toEqual(Duration.fromISO('PT30M')); - expect(usedSchedule?.timeout).toEqual(Duration.fromISO('PT3M')); + expect(usedSchedule?.frequency).toEqual({ minutes: 30 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); expect(addedProviders?.length).toEqual(1); expect(addedProviders?.pop()?.getProviderName()).toEqual( 'MicrosoftGraphOrgEntityProvider:customProviderId', diff --git a/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProviderConfig.test.ts b/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProviderConfig.test.ts index 8da0fb4150..86335cb97d 100644 --- a/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProviderConfig.test.ts +++ b/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProviderConfig.test.ts @@ -16,7 +16,6 @@ import { ConfigReader } from '@backstage/config'; import { readProviderConfigs } from './PuppetDbEntityProviderConfig'; -import { Duration } from 'luxon'; describe('readProviderConfigs', () => { afterEach(() => jest.resetAllMocks()); @@ -120,10 +119,8 @@ describe('readProviderConfigs', () => { expect(providerConfigs).toHaveLength(1); expect(providerConfigs[0].schedule).toEqual({ - frequency: Duration.fromISO('PT30M'), - timeout: { - minutes: 10, - }, + frequency: { minutes: 30 }, + timeout: { minutes: 10 }, }); }); }); From 1fbd77fb56fc9c1031ff1bd679a9e9c821c01338 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 19 Jun 2024 17:09:53 +0200 Subject: [PATCH 115/860] chore: small refactor to move the handlers out into an extension point Signed-off-by: blam --- .../package.json | 1 + .../src/autocomplete}/autocomplete.test.ts | 16 ++--- .../src/autocomplete}/autocomplete.ts | 34 +++++----- .../src/module.ts | 14 ++++- .../src/service/router.test.ts | 2 +- .../scaffolder-backend/src/service/router.ts | 31 +++++----- plugins/scaffolder-node/src/alpha.ts | 32 ++++++---- plugins/scaffolder-react/src/api/types.ts | 12 ++-- plugins/scaffolder/src/api.ts | 36 +++++++---- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 62 ++++++++++++------- 10 files changed, 144 insertions(+), 96 deletions(-) rename plugins/{scaffolder-backend/src/service => scaffolder-backend-module-bitbucket-cloud/src/autocomplete}/autocomplete.test.ts (81%) rename plugins/{scaffolder-backend/src/service => scaffolder-backend-module-bitbucket-cloud/src/autocomplete}/autocomplete.ts (69%) diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index f846f751cc..97a08e2741 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -46,6 +46,7 @@ "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", + "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", "node-fetch": "^2.6.7", diff --git a/plugins/scaffolder-backend/src/service/autocomplete.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts similarity index 81% rename from plugins/scaffolder-backend/src/service/autocomplete.test.ts rename to plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts index 53816f0126..50e218ce85 100644 --- a/plugins/scaffolder-backend/src/service/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts @@ -15,10 +15,10 @@ */ import { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; -import { handleBitbucketCloudRequest } from './autocomplete'; +import { handleAutocompleteRequest } from './autocomplete'; import { InputError } from '@backstage/errors'; -describe('handleBitbucketCloudRequest', () => { +describe('handleAutocompleteRequest', () => { const client: Partial = { listWorkspaces: jest.fn().mockReturnValue({ iteratePages: jest @@ -43,7 +43,7 @@ describe('handleBitbucketCloudRequest', () => { it('should pass the token to the client', async () => { const accessToken = 'foo'; - await handleBitbucketCloudRequest(accessToken, 'workspaces', {}); + await handleAutocompleteRequest(accessToken, 'workspaces', {}); expect(fromConfig).toHaveBeenCalledWith( expect.objectContaining({ accessToken }), @@ -51,13 +51,13 @@ describe('handleBitbucketCloudRequest', () => { }); it('should return workspaces', async () => { - const result = await handleBitbucketCloudRequest('foo', 'workspaces', {}); + const result = await handleAutocompleteRequest('foo', 'workspaces', {}); expect(result).toEqual(['workspace1']); }); it('should return projects', async () => { - const result = await handleBitbucketCloudRequest('foo', 'projects', { + const result = await handleAutocompleteRequest('foo', 'projects', { workspace: 'workspace1', }); @@ -65,7 +65,7 @@ describe('handleBitbucketCloudRequest', () => { }); it('should return repositories', async () => { - const result = await handleBitbucketCloudRequest('foo', 'repositories', { + const result = await handleAutocompleteRequest('foo', 'repositories', { workspace: 'workspace1', project: 'project1', }); @@ -75,13 +75,13 @@ describe('handleBitbucketCloudRequest', () => { it('should throw an error when passing an invalid resource', async () => { await expect( - handleBitbucketCloudRequest('token', 'invalid', {}), + handleAutocompleteRequest('token', 'invalid', {}), ).rejects.toThrow(InputError); }); it('should throw an error when there are missing parameters', async () => { await expect( - handleBitbucketCloudRequest('token', 'projects', {}), + handleAutocompleteRequest('token', 'projects', {}), ).rejects.toThrow(InputError); }); }); diff --git a/plugins/scaffolder-backend/src/service/autocomplete.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts similarity index 69% rename from plugins/scaffolder-backend/src/service/autocomplete.ts rename to plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts index 131305d53e..50723fb41d 100644 --- a/plugins/scaffolder-backend/src/service/autocomplete.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts @@ -17,11 +17,15 @@ import { InputError } from '@backstage/errors'; import { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; -export async function handleAutocompleteRequest( - token: string, - resource: string, - parameters: Record, -): Promise { +export async function handleAutocompleteRequest({ + resource, + token, + context, +}: { + resource: string; + token: string; + context: Record; +}): Promise<{ results: { title: string }[] }> { const client = BitbucketCloudClient.fromConfig({ host: 'bitbucket.org', apiBaseUrl: 'https://api.bitbucket.org/2.0', @@ -37,41 +41,41 @@ export async function handleAutocompleteRequest( result.push(...slugs); } - return result; + return { results: result.map(title => ({ title })) }; } case 'projects': { - if (!parameters.workspace) - throw new InputError('Missing workspace query parameter'); + if (!context.workspace) + throw new InputError('Missing workspace context parameter'); const result: string[] = []; for await (const page of client - .listProjectsByWorkspace(parameters.workspace) + .listProjectsByWorkspace(context.workspace) .iteratePages()) { const keys = [...page.values!].map(p => p.key!); result.push(...keys); } - return result; + return { results: result.map(title => ({ title })) }; } case 'repositories': { - if (!parameters.workspace || !parameters.project) + if (!context.workspace || !context.project) throw new InputError( - 'Missing workspace and/or project query parameter', + 'Missing workspace and/or project context parameter', ); const result: string[] = []; for await (const page of client - .listRepositoriesByWorkspace(parameters.workspace, { - q: `project.key="${parameters.project}"`, + .listRepositoriesByWorkspace(context.workspace, { + q: `project.key="${context.project}"`, }) .iteratePages()) { const slugs = [...page.values!].map(p => p.slug!); result.push(...slugs); } - return result; + return { results: result.map(title => ({ title })) }; } default: throw new InputError(`Invalid resource: ${resource}`); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/module.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/module.ts index 81afbf8c88..5bf49f7cd9 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/module.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/module.ts @@ -17,12 +17,16 @@ import { coreServices, createBackendModule, } from '@backstage/backend-plugin-api'; -import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; +import { + scaffolderActionsExtensionPoint, + scaffolderAutocompleteExtensionPoint, +} from '@backstage/plugin-scaffolder-node/alpha'; import { createBitbucketPipelinesRunAction, createPublishBitbucketCloudAction, } from './actions'; import { ScmIntegrations } from '@backstage/integration'; +import { handleAutocompleteRequest } from './autocomplete/autocomplete'; /** * @public @@ -35,15 +39,21 @@ export const bitbucketCloudModule = createBackendModule({ registerInit({ deps: { scaffolder: scaffolderActionsExtensionPoint, + autocomplete: scaffolderAutocompleteExtensionPoint, config: coreServices.rootConfig, }, - async init({ scaffolder, config }) { + async init({ scaffolder, config, autocomplete }) { const integrations = ScmIntegrations.fromConfig(config); scaffolder.addActions( createPublishBitbucketCloudAction({ integrations, config }), createBitbucketPipelinesRunAction({ integrations }), ); + + autocomplete.addAutocompleteProvider({ + id: 'bitbucket-cloud', + handler: handleAutocompleteRequest, + }); }, }); }, diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index f9ff1b2a04..10975d6b52 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -46,7 +46,7 @@ import { PermissionEvaluator, } from '@backstage/plugin-permission-common'; import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; -import { handleBitbucketCloudRequest } from './autocomplete'; +import { handleBitbucketCloudRequest } from '@backstage/plugin-scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete'; const mockAccess = jest.fn(); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index dbccd6ddb5..e5f88c3482 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -94,7 +94,7 @@ import { } from '@backstage/plugin-auth-node'; import { InternalTaskSecrets } from '../scaffolder/tasks/types'; import { checkPermission } from '../util/checkPermissions'; -import { handleBitbucketCloudRequest } from './autocomplete'; +import { AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; /** * @@ -167,6 +167,8 @@ export interface RouterOptions { httpAuth?: HttpAuthService; identity?: IdentityApi; discovery?: DiscoveryService; + + autocompleteHandlers?: Record; } function isSupportedTemplate(entity: TemplateEntityV1beta3) { @@ -274,6 +276,7 @@ export async function createRouter( permissionRules, discovery = HostDiscovery.fromConfig(config), identity = buildDefaultIdentityClient(options), + autocompleteHandlers = {}, } = options; const { auth, httpAuth } = createLegacyAuthAdapters({ @@ -773,28 +776,22 @@ export async function createRouter( })), }); }) - .get('/v2/autocomplete/:provider/:resource', async (req, res) => { - const { token, ...query } = req.query; + .post('/v2/autocomplete/:provider/:resource', async (req, res) => { + const { token, context } = req.body; const { provider, resource } = req.params; if (!token) throw new InputError('Missing token query parameter'); - let result: string[]; - - switch (provider) { - case 'bitbucketCloud': { - result = await handleBitbucketCloudRequest( - token as string, - resource, - query as Record, - ); - break; - } - default: - throw new InputError(`Unsupported provider: ${provider}`); + if (!autocompleteHandlers[provider]) { + throw new InputError(`Unsupported provider: ${provider}`); } + const { results } = await autocompleteHandlers[provider]({ + resource, + token, + context, + }); - res.status(200).json(result); + res.status(200).json({ results }); }); const app = express(); diff --git a/plugins/scaffolder-node/src/alpha.ts b/plugins/scaffolder-node/src/alpha.ts index 3644d48b7c..ef4d5ab289 100644 --- a/plugins/scaffolder-node/src/alpha.ts +++ b/plugins/scaffolder-node/src/alpha.ts @@ -80,22 +80,32 @@ export const scaffolderTemplatingExtensionPoint = id: 'scaffolder.templating', }); +/** + * Autocomplete handler for the scaffolder. + * @alpha + */ +export type AutocompleteHandler = ({ + resource, + token, + context, +}: { + resource: string; + token: string; + context: Record; +}) => Promise<{ results: { title: string }[] }>; + /** * Extension point for adding autocomplete handler providers * @alpha */ export interface ScaffolderAutocompleteExtensionPoint { - addAutocompleteProvider( - provider: ({ - type, - token, - query, - }: { - type: string; - token: string; - query: Record; - }) => Promise<{ results: { title: string }[] }>, - ): void; + addAutocompleteProvider({ + id, + handler, + }: { + id: string; + handler: AutocompleteHandler; + }): void; } /** diff --git a/plugins/scaffolder-react/src/api/types.ts b/plugins/scaffolder-react/src/api/types.ts index c79f98c780..eaef54ff1b 100644 --- a/plugins/scaffolder-react/src/api/types.ts +++ b/plugins/scaffolder-react/src/api/types.ts @@ -230,10 +230,10 @@ export interface ScaffolderApi { dryRun?(options: ScaffolderDryRunOptions): Promise; - autocomplete( - token: string, - provider: string, - resource: string, - params?: Record, - ): Promise; + autocomplete?(options: { + token: string; + provider: string; + resource: string; + context?: Record; + }): Promise<{ results: { title: string }[] }>; } diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index ff5c89e91e..1809ed4c15 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -338,27 +338,37 @@ export class ScaffolderClient implements ScaffolderApi { return await response.json(); } - async autocomplete( - token: string, - provider: string, - resource: string, - params?: Record, - ): Promise { + async autocomplete({ + token, + resource, + provider, + context, + }: { + token: string; + provider: string; + resource: string; + context?: Record; + }): Promise<{ results: { title: string }[] }> { const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const query = new URLSearchParams({ - ...params, - token, - }); - const url = `${baseUrl}/v2/autocomplete/${provider}/${resource}?${query}`; + + const url = `${baseUrl}/v2/autocomplete/${provider}/${resource}`; const response = await this.fetchApi.fetch(url, { - method: 'GET', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + token, + context: context ?? {}, + }), }); if (!response.ok) { throw await ResponseError.fromResponse(response); } - return await response.json(); + const { results } = await response.json(); + return { results }; } } diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 51bd1f5c67..10d4a6e6c3 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -72,14 +72,19 @@ export const BitbucketRepoPicker = (props: { useDebounce( () => { const updateAvailableWorkspaces = async () => { - if (host === 'bitbucket.org' && accessToken) { - const result = await scaffolderApi.autocomplete( - accessToken, - 'bitbucketCloud', - 'workspaces', - ); + if ( + host === 'bitbucket.org' && + accessToken && + scaffolderApi.autocomplete + ) { + const { results } = await scaffolderApi.autocomplete({ + token: accessToken, + resource: 'workspaces', + context: {}, + provider: 'bitbucket-cloud', + }); - setAvailableWorkspaces(result); + setAvailableWorkspaces(results.map(r => r.title)); } else { setAvailableWorkspaces([]); } @@ -95,15 +100,20 @@ export const BitbucketRepoPicker = (props: { useDebounce( () => { const updateAvailableProjects = async () => { - if (host === 'bitbucket.org' && accessToken && workspace) { - const result = await scaffolderApi.autocomplete( - accessToken, - 'bitbucketCloud', - 'projects', - { workspace }, - ); + if ( + host === 'bitbucket.org' && + accessToken && + workspace && + scaffolderApi.autocomplete + ) { + const { results } = await scaffolderApi.autocomplete({ + token: accessToken, + resource: 'projects', + context: { workspace }, + provider: 'bitbucket-cloud', + }); - setAvailableProjects(result); + setAvailableProjects(results.map(r => r.title)); } else { setAvailableProjects([]); } @@ -119,15 +129,21 @@ export const BitbucketRepoPicker = (props: { useDebounce( () => { const updateAvailableRepositories = async () => { - if (host === 'bitbucket.org' && accessToken && workspace && project) { - const availableRepos = await scaffolderApi.autocomplete( - accessToken, - 'bitbucketCloud', - 'repositories', - { workspace, project }, - ); + if ( + host === 'bitbucket.org' && + accessToken && + workspace && + project && + scaffolderApi.autocomplete + ) { + const { results } = await scaffolderApi.autocomplete({ + token: accessToken, + resource: 'repositories', + context: { workspace, project }, + provider: 'bitbucket-cloud', + }); - onChange({ availableRepos }); + onChange({ availableRepos: results.map(r => r.title) }); } else { onChange({ availableRepos: [] }); } From 16acc0fc10a1879e19075c5ce0f8900b6c5263b6 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 19 Jun 2024 17:10:11 +0200 Subject: [PATCH 116/860] chore: pass through the handlers to the autocomplete Signed-off-by: blam --- plugins/scaffolder-backend/src/ScaffolderPlugin.ts | 6 ++++-- plugins/scaffolder-backend/src/service/router.test.ts | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index 9fc4b2537a..c83c6d437d 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -28,6 +28,7 @@ import { TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; import { + AutocompleteHandler, scaffolderActionsExtensionPoint, scaffolderAutocompleteExtensionPoint, scaffolderTaskBrokerExtensionPoint, @@ -83,10 +84,10 @@ export const scaffolderPlugin = createBackendPlugin({ }, }); - const autocompleteResolers = []; + const autocompleteHandlers: Record = {}; env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, { addAutocompleteProvider(provider) { - autocompleteResolers.push(provider); + autocompleteHandlers[provider.id] = provider.handler; }, }); @@ -170,6 +171,7 @@ export const scaffolderPlugin = createBackendPlugin({ httpAuth, discovery, permissions, + autocompleteHandlers, }); httpRouter.use(router); }, diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 10975d6b52..4bd3847666 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -46,7 +46,6 @@ import { PermissionEvaluator, } from '@backstage/plugin-permission-common'; import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; -import { handleBitbucketCloudRequest } from '@backstage/plugin-scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete'; const mockAccess = jest.fn(); From dcacad5d81c4bae38aab028006ad1fd1f315d2e2 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Thu, 6 Jun 2024 20:15:46 -0400 Subject: [PATCH 117/860] docs: update catalog error eventing/logging Signed-off-by: Christopher Diaz --- .../software-catalog/life-of-an-entity.md | 124 +++++++++++++++++- 1 file changed, 120 insertions(+), 4 deletions(-) diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 13fe496fc1..9c45bec814 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -197,13 +197,15 @@ cannot be parsed successfully, etc. There are two main ways that these errors are surfaced. -First, the catalog backend will produce detailed logs that should contain -sufficient information for a reader to find the causes for errors. Since these -logs are typically not easily found by end users, this can mainly be a useful +First, the catalog backend will emit [events](https://github.com/backstage/backstage/tree/master/plugins/events-node) you can subscribe to that should contain +sufficient information for a reader to find the causes for errors. +Since these events are typically not easily found by end users, this can mainly be a useful tool for Backstage operators who want to debug problems either with statically registered entities that are under their control, or to help end users find problems. +> Prior to Backstage version v1.26.0 and `@backstage/plugin-catalog-backend` v1.21.9 catalog errors were logged by default. See the docs below on how to enable these logs and an example on how you can further customize how you ingest these errors. + Second, for most classes of errors, the entity itself will contain a status field that describes the problem. The contents of this field is shown at the top of your entity page in Backstage, if you have placed the corresponding error @@ -212,6 +214,118 @@ callout component (`EntityProcessingErrorsPanel`) there. We are still working to improve the surfacing and observability around processing loop errors. +### Subscribing to Catalog Errors + +Errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them. + +#### New Backend System + +Make sure you have the events plugin installed. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend/alpha')); +``` + +Create a backend module that subscribes to the catalog error events. The topic is `experimental.catalog.errors`. + +```ts title="packages/backend/src/index.ts" +import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend'; +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { eventsServiceRef, EventParams } from '@backstage/plugin-events-node'; + +interface EventsPayload { + entity: string; + location?: string; + errors: Error[]; +} + +interface EventsParamsWithPayload extends EventParams { + eventPayload: EventsPayload; +} + +const eventsModuleCatalogErrors = createBackendModule({ + pluginId: 'events', + moduleId: 'catalog-errors', + register(env) { + env.registerInit({ + deps: { + events: eventsServiceRef, + logger: coreServices.logger, + }, + async init({ events, logger }) { + events.subscribe({ + id: 'catalog', + topics: [CATALOG_ERRORS_TOPIC], + async onEvent(params: EventParams): Promise { + const event = params as EventsParamsWithPayload; + const { entity, location, errors } = event.eventPayload; + for (const error of errors) { + logger.warn(error.message, { + entity, + location, + }); + } + }, + }); + }, + }); + }, +}); +``` + +Now install your module. + +```ts title="packages/backend/src/index.ts" +backend.add(eventsModuleCatalogErrors); +``` + +You should now see logs as the catalog emits events. + +``` +[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml +``` + +#### Legacy Backend + +Make sure you have the events plugin installed. See the legacy backend instructions [here](https://github.com/backstage/backstage/tree/master/plugins/events-node#legacy-backend-system). + +Subscribe to the events using the `eventBroker` set in the environment. + +```ts +import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend'; + +env.eventBroker.subscribe({ + supportsEventTopics(): string[] { + return [CATALOG_ERRORS_TOPIC]; + }, + + async onEvent( + params: EventParams<{ + entity: string; + location?: string; + errors: Array; + }>, + ): Promise { + const { entity, location, errors } = params.eventPayload; + for (const error of errors) { + env.logger.warn(error.message, { + entity, + location, + }); + } + }, +}); +``` + +You should now see logs as the catalog emits events. + +``` +[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml +``` + ## Orphaning As mentioned earlier, entities internally form a graph. The edges go from @@ -268,8 +382,10 @@ However, if you want to delete orphaned entities automatically anyway, you can enable the automated clean up with the following app-config option. ``` + catalog: - orphanStrategy: delete +orphanStrategy: delete + ``` ## Implicit Deletion From 9809a3aadd232b5c74dc42871917ca48cd7e8cc4 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Thu, 6 Jun 2024 20:28:19 -0400 Subject: [PATCH 118/860] fix formatting Signed-off-by: Christopher Diaz --- docs/features/software-catalog/life-of-an-entity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 9c45bec814..3db33bf42b 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -384,7 +384,7 @@ enable the automated clean up with the following app-config option. ``` catalog: -orphanStrategy: delete + orphanStrategy: delete ``` From 12694f9a55b2550ed65d9d897067e843ecac80da Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Thu, 6 Jun 2024 20:28:39 -0400 Subject: [PATCH 119/860] fix formatting Signed-off-by: Christopher Diaz --- docs/features/software-catalog/life-of-an-entity.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 3db33bf42b..6dfb656c4b 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -382,10 +382,8 @@ However, if you want to delete orphaned entities automatically anyway, you can enable the automated clean up with the following app-config option. ``` - catalog: orphanStrategy: delete - ``` ## Implicit Deletion From e2de06cf344ab9739a4e047b7df5f5a15f85e8b0 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Thu, 6 Jun 2024 20:29:45 -0400 Subject: [PATCH 120/860] specify the log is an example Signed-off-by: Christopher Diaz --- docs/features/software-catalog/life-of-an-entity.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 6dfb656c4b..017b5322be 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -282,7 +282,7 @@ Now install your module. backend.add(eventsModuleCatalogErrors); ``` -You should now see logs as the catalog emits events. +You should now see logs as the catalog emits events. Example: ``` [1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml @@ -320,7 +320,7 @@ env.eventBroker.subscribe({ }); ``` -You should now see logs as the catalog emits events. +You should now see logs as the catalog emits events. Example: ``` [1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml From 6dbe3921ca0fc383f32893f017840c24593c5942 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 11:17:10 -0400 Subject: [PATCH 121/860] update docs Signed-off-by: Christopher Diaz --- .../software-catalog/configuration.md | 79 ++++++++++++ .../software-catalog/life-of-an-entity.md | 116 +----------------- 2 files changed, 81 insertions(+), 114 deletions(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 61366a91f7..54a2b99faf 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -177,3 +177,82 @@ here. Setting this value too low risks exhausting rate limits on external systems that are queried by processors, such as version control systems housing catalog-info files. + +## Subscribing to Catalog Errors + +Catalog errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them. + +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 +yarn --cwd packages/backend add @backstage/plugin-events-node +``` + +Now you can install the events backend plugin in your backend. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend/alpha')); +``` + +Next, create a backend module that subscribes to the catalog error events. The topic is `experimental.catalog.errors`. + +```ts title="packages/backend/src/index.ts" +import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend'; +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { eventsServiceRef, EventParams } from '@backstage/plugin-events-node'; + +interface EventsPayload { + entity: string; + location?: string; + errors: Error[]; +} + +interface EventsParamsWithPayload extends EventParams { + eventPayload: EventsPayload; +} + +const eventsModuleCatalogErrors = createBackendModule({ + pluginId: 'events', + moduleId: 'catalog-errors', + register(env) { + env.registerInit({ + deps: { + events: eventsServiceRef, + logger: coreServices.logger, + }, + async init({ events, logger }) { + events.subscribe({ + id: 'catalog', + topics: [CATALOG_ERRORS_TOPIC], + async onEvent(params: EventParams): Promise { + const event = params as EventsParamsWithPayload; + const { entity, location, errors } = event.eventPayload; + for (const error of errors) { + logger.warn(error.message, { + entity, + location, + }); + } + }, + }); + }, + }); + }, +}); +``` + +Now install your module. + +```ts title="packages/backend/src/index.ts" +backend.add(eventsModuleCatalogErrors); +``` + +You should now see logs as the catalog emits events. Example: + +``` +[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml +``` diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 017b5322be..029778510a 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -197,8 +197,8 @@ cannot be parsed successfully, etc. There are two main ways that these errors are surfaced. -First, the catalog backend will emit [events](https://github.com/backstage/backstage/tree/master/plugins/events-node) you can subscribe to that should contain -sufficient information for a reader to find the causes for errors. +First, the catalog backend will emit events using the [events backend plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node). You can subscribe to the events. The events should contain +sufficient information for a reader to find the causes for errors. See the configuration documentation [here](./configuration.md#subscribing-to-catalog-errors) for how to subscribe and log these error events. Since these events are typically not easily found by end users, this can mainly be a useful tool for Backstage operators who want to debug problems either with statically registered entities that are under their control, or to help end users find @@ -214,118 +214,6 @@ callout component (`EntityProcessingErrorsPanel`) there. We are still working to improve the surfacing and observability around processing loop errors. -### Subscribing to Catalog Errors - -Errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them. - -#### New Backend System - -Make sure you have the events plugin installed. - -```ts title="packages/backend/src/index.ts" -backend.add(import('@backstage/plugin-events-backend/alpha')); -``` - -Create a backend module that subscribes to the catalog error events. The topic is `experimental.catalog.errors`. - -```ts title="packages/backend/src/index.ts" -import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend'; -import { - coreServices, - createBackendModule, -} from '@backstage/backend-plugin-api'; -import { eventsServiceRef, EventParams } from '@backstage/plugin-events-node'; - -interface EventsPayload { - entity: string; - location?: string; - errors: Error[]; -} - -interface EventsParamsWithPayload extends EventParams { - eventPayload: EventsPayload; -} - -const eventsModuleCatalogErrors = createBackendModule({ - pluginId: 'events', - moduleId: 'catalog-errors', - register(env) { - env.registerInit({ - deps: { - events: eventsServiceRef, - logger: coreServices.logger, - }, - async init({ events, logger }) { - events.subscribe({ - id: 'catalog', - topics: [CATALOG_ERRORS_TOPIC], - async onEvent(params: EventParams): Promise { - const event = params as EventsParamsWithPayload; - const { entity, location, errors } = event.eventPayload; - for (const error of errors) { - logger.warn(error.message, { - entity, - location, - }); - } - }, - }); - }, - }); - }, -}); -``` - -Now install your module. - -```ts title="packages/backend/src/index.ts" -backend.add(eventsModuleCatalogErrors); -``` - -You should now see logs as the catalog emits events. Example: - -``` -[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml -``` - -#### Legacy Backend - -Make sure you have the events plugin installed. See the legacy backend instructions [here](https://github.com/backstage/backstage/tree/master/plugins/events-node#legacy-backend-system). - -Subscribe to the events using the `eventBroker` set in the environment. - -```ts -import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend'; - -env.eventBroker.subscribe({ - supportsEventTopics(): string[] { - return [CATALOG_ERRORS_TOPIC]; - }, - - async onEvent( - params: EventParams<{ - entity: string; - location?: string; - errors: Array; - }>, - ): Promise { - const { entity, location, errors } = params.eventPayload; - for (const error of errors) { - env.logger.warn(error.message, { - entity, - location, - }); - } - }, -}); -``` - -You should now see logs as the catalog emits events. Example: - -``` -[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml -``` - ## Orphaning As mentioned earlier, entities internally form a graph. The edges go from From 21bef93e3535d310abea47bd1173e6ba0a0d4539 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 11:52:48 -0400 Subject: [PATCH 122/860] add logging module to make this easier for users but retain custom docs Signed-off-by: Christopher Diaz --- .../software-catalog/configuration.md | 29 ++++++--- .../catalog-backend-module-logs/.eslintrc.js | 1 + plugins/catalog-backend-module-logs/README.md | 30 +++++++++ .../catalog-info.yaml | 10 +++ .../catalog-backend-module-logs/package.json | 39 ++++++++++++ .../catalog-backend-module-logs/src/index.ts | 23 +++++++ .../catalog-backend-module-logs/src/module.ts | 61 +++++++++++++++++++ yarn.lock | 13 ++++ 8 files changed, 199 insertions(+), 7 deletions(-) create mode 100644 plugins/catalog-backend-module-logs/.eslintrc.js create mode 100644 plugins/catalog-backend-module-logs/README.md create mode 100644 plugins/catalog-backend-module-logs/catalog-info.yaml create mode 100644 plugins/catalog-backend-module-logs/package.json create mode 100644 plugins/catalog-backend-module-logs/src/index.ts create mode 100644 plugins/catalog-backend-module-logs/src/module.ts diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 54a2b99faf..4bab2313b8 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -195,7 +195,27 @@ Now you can install the events backend plugin in your backend. backend.add(import('@backstage/plugin-events-backend/alpha')); ``` -Next, create a backend module that subscribes to the catalog error events. The topic is `experimental.catalog.errors`. +### Logging Errors + +If you want to log catalog errors you can install the `@backstage/plugin-catalog-backend-module-logs` module. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend-module-logs')); +``` + +This will log errors with a level of `warn`. + +You should now see logs as the catalog emits events. Example: + +``` +[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml +``` + +### Custom Error Handling + +If you wish to handle catalog errors with logic the following should help you get started. + +Create a backend module that subscribes to the catalog error events. The topic is `experimental.catalog.errors`. ```ts title="packages/backend/src/index.ts" import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend'; @@ -231,6 +251,7 @@ const eventsModuleCatalogErrors = createBackendModule({ async onEvent(params: EventParams): Promise { const event = params as EventsParamsWithPayload; const { entity, location, errors } = event.eventPayload; + // Add custom logic here for responding to errors for (const error of errors) { logger.warn(error.message, { entity, @@ -250,9 +271,3 @@ Now install your module. ```ts title="packages/backend/src/index.ts" backend.add(eventsModuleCatalogErrors); ``` - -You should now see logs as the catalog emits events. Example: - -``` -[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml -``` diff --git a/plugins/catalog-backend-module-logs/.eslintrc.js b/plugins/catalog-backend-module-logs/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/catalog-backend-module-logs/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/catalog-backend-module-logs/README.md b/plugins/catalog-backend-module-logs/README.md new file mode 100644 index 0000000000..6c84114306 --- /dev/null +++ b/plugins/catalog-backend-module-logs/README.md @@ -0,0 +1,30 @@ +# backstage-plugin-catalog-backend-module-logs + +A module that subscribes to catalog related events and logs them. + +Catalog errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them. + +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 +yarn --cwd packages/backend add @backstage/plugin-events-node +``` + +Now you can install the events backend plugin in your backend. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend/alpha')); +``` + +Now install the catalog logs module. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend-module-logs')); +``` + +You should now see logs as the catalog emits events. Example: + +``` +[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml +``` diff --git a/plugins/catalog-backend-module-logs/catalog-info.yaml b/plugins/catalog-backend-module-logs/catalog-info.yaml new file mode 100644 index 0000000000..f2223174c3 --- /dev/null +++ b/plugins/catalog-backend-module-logs/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-catalog-backend-module-logs + title: '@backstage/plugin-catalog-backend-module-logs' + description: A module that subscribes to catalog releated events and logs them. +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json new file mode 100644 index 0000000000..f35a8b7816 --- /dev/null +++ b/plugins/catalog-backend-module-logs/package.json @@ -0,0 +1,39 @@ +{ + "name": "@backstage/plugin-catalog-backend-module-logs", + "description": "A module that subscribes to catalog releated events and logs them.", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": true, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-events-node": "workspace:^" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/catalog-backend-module-logs/src/index.ts b/plugins/catalog-backend-module-logs/src/index.ts new file mode 100644 index 0000000000..3d5f606d27 --- /dev/null +++ b/plugins/catalog-backend-module-logs/src/index.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** + * The logs backend module for the catalog plugin. + * + * @packageDocumentation + */ + +export { catalogModuleLogs as default } from './module'; diff --git a/plugins/catalog-backend-module-logs/src/module.ts b/plugins/catalog-backend-module-logs/src/module.ts new file mode 100644 index 0000000000..0f41d2e1a6 --- /dev/null +++ b/plugins/catalog-backend-module-logs/src/module.ts @@ -0,0 +1,61 @@ +/* + * 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 { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend'; +import { eventsServiceRef, EventParams } from '@backstage/plugin-events-node'; + +interface EventsPayload { + entity: string; + location?: string; + errors: Error[]; +} + +interface EventsParamsWithPayload extends EventParams { + eventPayload: EventsPayload; +} + +export const catalogModuleLogs = createBackendModule({ + pluginId: 'catalog', + moduleId: 'logs', + register(env) { + env.registerInit({ + deps: { + events: eventsServiceRef, + logger: coreServices.logger, + }, + async init({ events, logger }) { + events.subscribe({ + id: 'catalog', + topics: [CATALOG_ERRORS_TOPIC], + async onEvent(params: EventParams): Promise { + const event = params as EventsParamsWithPayload; + const { entity, location, errors } = event.eventPayload; + for (const error of errors) { + logger.warn(error.message, { + entity, + location, + }); + } + }, + }); + }, + }); + }, +}); diff --git a/yarn.lock b/yarn.lock index a0a385ca66..542d9242da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5440,6 +5440,19 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-catalog-backend-module-logs@workspace:plugins/catalog-backend-module-logs": + version: 0.0.0-use.local + resolution: "@backstage/plugin-catalog-backend-module-logs@workspace:plugins/catalog-backend-module-logs" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + languageName: unknown + linkType: soft + "@backstage/plugin-catalog-backend-module-msgraph@workspace:plugins/catalog-backend-module-msgraph": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-backend-module-msgraph@workspace:plugins/catalog-backend-module-msgraph" From 97caf558236a4d2d9ac8029a186607cb9deddd4c Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 11:56:36 -0400 Subject: [PATCH 123/860] add logging module to make this easier for users but retain custom docs Signed-off-by: Christopher Diaz --- .changeset/ten-pots-walk.md | 39 +++++++++++++++++++ .../software-catalog/configuration.md | 9 +++++ plugins/catalog-backend-module-logs/README.md | 9 +++++ 3 files changed, 57 insertions(+) create mode 100644 .changeset/ten-pots-walk.md diff --git a/.changeset/ten-pots-walk.md b/.changeset/ten-pots-walk.md new file mode 100644 index 0000000000..6265e8dd7f --- /dev/null +++ b/.changeset/ten-pots-walk.md @@ -0,0 +1,39 @@ +--- +'@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. + +Catalog errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them. + +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 +yarn --cwd packages/backend add @backstage/plugin-events-node +``` + +Now you can install the events backend plugin in your backend. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend/alpha')); +``` + +Install the catalog logs module. + +```ts +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs +``` + +Now install the catalog logs module. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend-module-logs')); +``` + +You should now see logs as the catalog emits events. Example: + +``` +[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml +``` diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 4bab2313b8..9805eb06dd 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -199,6 +199,15 @@ backend.add(import('@backstage/plugin-events-backend/alpha')); If you want to log catalog errors you can install the `@backstage/plugin-catalog-backend-module-logs` module. +Install the catalog logs module. + +```ts +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs +``` + +Add the module to your backend. + ```ts title="packages/backend/src/index.ts" backend.add(import('@backstage/plugin-catalog-backend-module-logs')); ``` diff --git a/plugins/catalog-backend-module-logs/README.md b/plugins/catalog-backend-module-logs/README.md index 6c84114306..7e20a0161b 100644 --- a/plugins/catalog-backend-module-logs/README.md +++ b/plugins/catalog-backend-module-logs/README.md @@ -13,6 +13,15 @@ yarn --cwd packages/backend add @backstage/plugin-events-node Now you can install the events backend plugin in your backend. +Install the catalog logs module. + +```ts +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs +``` + +Add the module to your backend. + ```ts title="packages/backend/src/index.ts" backend.add(import('@backstage/plugin-events-backend/alpha')); ``` From c4c81bcc73446a29c6cda5456ffded2698c8a816 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 11:57:41 -0400 Subject: [PATCH 124/860] add logging module to make this easier for users but retain custom docs Signed-off-by: Christopher Diaz --- .changeset/ten-pots-walk.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/ten-pots-walk.md b/.changeset/ten-pots-walk.md index 6265e8dd7f..e8f68afbe0 100644 --- a/.changeset/ten-pots-walk.md +++ b/.changeset/ten-pots-walk.md @@ -26,7 +26,7 @@ Install the catalog logs module. yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs ``` -Now install the catalog logs module. +Add the module to your backend. ```ts title="packages/backend/src/index.ts" backend.add(import('@backstage/plugin-catalog-backend-module-logs')); From 9c8518e29a1c1d40bf096f7a5e44ace9c4e70449 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 12:00:10 -0400 Subject: [PATCH 125/860] module should not be private Signed-off-by: Christopher Diaz --- .../catalog-backend-module-logs/package.json | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index f35a8b7816..3d07b115ae 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,27 +1,29 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "description": "A module that subscribes to catalog releated events and logs them.", "version": "0.0.0", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "private": true, + "description": "A module that subscribes to catalog releated events and logs them.", + "backstage": { + "role": "backend-plugin-module" + }, "publishConfig": { "access": "public", "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, - "backstage": { - "role": "backend-plugin-module" - }, + "license": "Apache-2.0", + "main": "src/index.ts", + "types": "src/index.ts", + "files": [ + "dist" + ], "scripts": { - "start": "backstage-cli package start", "build": "backstage-cli package build", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack" + "postpack": "backstage-cli package postpack", + "start": "backstage-cli package start", + "test": "backstage-cli package test" }, "dependencies": { "@backstage/backend-common": "workspace:^", @@ -32,8 +34,5 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^" - }, - "files": [ - "dist" - ] + } } From acb3c93b4ce5be9bbc4ed5d2ac4a9ab912bb908f Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 12:10:05 -0400 Subject: [PATCH 126/860] add api report Signed-off-by: Christopher Diaz --- plugins/catalog-backend-module-logs/api-report.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 plugins/catalog-backend-module-logs/api-report.md diff --git a/plugins/catalog-backend-module-logs/api-report.md b/plugins/catalog-backend-module-logs/api-report.md new file mode 100644 index 0000000000..abad6c3095 --- /dev/null +++ b/plugins/catalog-backend-module-logs/api-report.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/plugin-catalog-backend-module-logs" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; + +// Warning: (ae-missing-release-tag) "catalogModuleLogs" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +const catalogModuleLogs: () => BackendFeature; +export default catalogModuleLogs; +``` From d9772b13cb1f37dca41b4219dc466ebe59916c72 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 12:17:27 -0400 Subject: [PATCH 127/860] add api report Signed-off-by: Christopher Diaz --- plugins/catalog-backend-module-logs/src/index.ts | 1 + plugins/catalog-backend-module-logs/src/module.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/plugins/catalog-backend-module-logs/src/index.ts b/plugins/catalog-backend-module-logs/src/index.ts index 3d5f606d27..6808046373 100644 --- a/plugins/catalog-backend-module-logs/src/index.ts +++ b/plugins/catalog-backend-module-logs/src/index.ts @@ -18,6 +18,7 @@ * The logs backend module for the catalog plugin. * * @packageDocumentation + * @public */ export { catalogModuleLogs as default } from './module'; diff --git a/plugins/catalog-backend-module-logs/src/module.ts b/plugins/catalog-backend-module-logs/src/module.ts index 0f41d2e1a6..13a96a64f8 100644 --- a/plugins/catalog-backend-module-logs/src/module.ts +++ b/plugins/catalog-backend-module-logs/src/module.ts @@ -14,6 +14,11 @@ * limitations under the License. */ +/** + * Logs catalog errors from events. + * + * @public + */ import { coreServices, createBackendModule, From 4118216077183039f33434011b0fc9cd0b7cdf8a Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 12:22:25 -0400 Subject: [PATCH 128/860] add api report Signed-off-by: Christopher Diaz --- plugins/catalog-backend-module-logs/package.json | 5 +++++ plugins/catalog-backend-module-logs/src/index.ts | 3 +-- plugins/catalog-backend-module-logs/src/module.ts | 2 -- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index 3d07b115ae..d2e76131fb 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -10,6 +10,11 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/catalog-backend-module-logs" + }, "license": "Apache-2.0", "main": "src/index.ts", "types": "src/index.ts", diff --git a/plugins/catalog-backend-module-logs/src/index.ts b/plugins/catalog-backend-module-logs/src/index.ts index 6808046373..717b7bde9e 100644 --- a/plugins/catalog-backend-module-logs/src/index.ts +++ b/plugins/catalog-backend-module-logs/src/index.ts @@ -16,9 +16,8 @@ /** * The logs backend module for the catalog plugin. - * - * @packageDocumentation * @public + * @packageDocumentation */ export { catalogModuleLogs as default } from './module'; diff --git a/plugins/catalog-backend-module-logs/src/module.ts b/plugins/catalog-backend-module-logs/src/module.ts index 13a96a64f8..84f92cfe92 100644 --- a/plugins/catalog-backend-module-logs/src/module.ts +++ b/plugins/catalog-backend-module-logs/src/module.ts @@ -16,8 +16,6 @@ /** * Logs catalog errors from events. - * - * @public */ import { coreServices, From abeb6b982ea01473e15207af6c7ae1a80392b75e Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 12:27:24 -0400 Subject: [PATCH 129/860] add api report without warnings Signed-off-by: Christopher Diaz --- plugins/catalog-backend-module-logs/api-report.md | 2 -- plugins/catalog-backend-module-logs/src/index.ts | 5 ++--- plugins/catalog-backend-module-logs/src/module.ts | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/plugins/catalog-backend-module-logs/api-report.md b/plugins/catalog-backend-module-logs/api-report.md index abad6c3095..7dd45e6119 100644 --- a/plugins/catalog-backend-module-logs/api-report.md +++ b/plugins/catalog-backend-module-logs/api-report.md @@ -5,8 +5,6 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; -// Warning: (ae-missing-release-tag) "catalogModuleLogs" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) const catalogModuleLogs: () => BackendFeature; export default catalogModuleLogs; diff --git a/plugins/catalog-backend-module-logs/src/index.ts b/plugins/catalog-backend-module-logs/src/index.ts index 717b7bde9e..77a7d424eb 100644 --- a/plugins/catalog-backend-module-logs/src/index.ts +++ b/plugins/catalog-backend-module-logs/src/index.ts @@ -15,9 +15,8 @@ */ /** - * The logs backend module for the catalog plugin. - * @public + * A catalog module that logs catalog errors using the logger service. + * * @packageDocumentation */ - export { catalogModuleLogs as default } from './module'; diff --git a/plugins/catalog-backend-module-logs/src/module.ts b/plugins/catalog-backend-module-logs/src/module.ts index 84f92cfe92..54fc428cdf 100644 --- a/plugins/catalog-backend-module-logs/src/module.ts +++ b/plugins/catalog-backend-module-logs/src/module.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -/** - * Logs catalog errors from events. - */ import { coreServices, createBackendModule, @@ -34,6 +31,7 @@ interface EventsParamsWithPayload extends EventParams { eventPayload: EventsPayload; } +/** @public */ export const catalogModuleLogs = createBackendModule({ pluginId: 'catalog', moduleId: 'logs', From 486ce82f7fa799725408728ee6dc04da541a81f8 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 14:07:22 -0400 Subject: [PATCH 130/860] add basic test Signed-off-by: Christopher Diaz --- .../catalog-backend-module-logs/package.json | 3 +- .../src/module.test.ts | 45 +++++++++++++++++++ yarn.lock | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 plugins/catalog-backend-module-logs/src/module.test.ts diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index d2e76131fb..879ed3176a 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -38,6 +38,7 @@ }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^" } } diff --git a/plugins/catalog-backend-module-logs/src/module.test.ts b/plugins/catalog-backend-module-logs/src/module.test.ts new file mode 100644 index 0000000000..733474512e --- /dev/null +++ b/plugins/catalog-backend-module-logs/src/module.test.ts @@ -0,0 +1,45 @@ +/* + * 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 { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { catalogModuleLogs } from './module'; +import { createServiceFactory } from '@backstage/backend-plugin-api'; +import { TestEventsService } from '@backstage/plugin-events-backend-test-utils'; +import { eventsServiceRef } from '@backstage/plugin-events-node'; + +describe('eventsModuleLogs', () => { + it('should be correctly wired and set up', async () => { + const events = new TestEventsService(); + const eventsServiceFactory = createServiceFactory({ + service: eventsServiceRef, + deps: {}, + async factory({}) { + return events; + }, + }); + + await startTestBackend({ + features: [ + mockServices.logger.factory(), + eventsServiceFactory(), + catalogModuleLogs(), + ], + }); + + expect(events.subscribed).toHaveLength(1); + expect(events.subscribed[0].id).toEqual('catalog'); + }); +}); diff --git a/yarn.lock b/yarn.lock index 542d9242da..6c298b9c89 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5449,6 +5449,7 @@ __metadata: "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" "@backstage/plugin-events-node": "workspace:^" languageName: unknown linkType: soft From 5f4090221f598ddfb101db3a629dcf577157edf0 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Fri, 7 Jun 2024 14:08:31 -0400 Subject: [PATCH 131/860] add basic test Signed-off-by: Christopher Diaz --- plugins/catalog-backend-module-logs/src/module.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-logs/src/module.test.ts b/plugins/catalog-backend-module-logs/src/module.test.ts index 733474512e..79f1b8c295 100644 --- a/plugins/catalog-backend-module-logs/src/module.test.ts +++ b/plugins/catalog-backend-module-logs/src/module.test.ts @@ -20,7 +20,7 @@ import { createServiceFactory } from '@backstage/backend-plugin-api'; import { TestEventsService } from '@backstage/plugin-events-backend-test-utils'; import { eventsServiceRef } from '@backstage/plugin-events-node'; -describe('eventsModuleLogs', () => { +describe('catalogModuleLogs', () => { it('should be correctly wired and set up', async () => { const events = new TestEventsService(); const eventsServiceFactory = createServiceFactory({ From 916449c0452b6e80df5b8a40ed4f3236f84f8d2b Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 10:08:20 -0400 Subject: [PATCH 132/860] Update docs/features/software-catalog/life-of-an-entity.md Co-authored-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Signed-off-by: Christopher Diaz --- docs/features/software-catalog/life-of-an-entity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 029778510a..d333b90565 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -198,7 +198,7 @@ cannot be parsed successfully, etc. There are two main ways that these errors are surfaced. First, the catalog backend will emit events using the [events backend plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node). You can subscribe to the events. The events should contain -sufficient information for a reader to find the causes for errors. See the configuration documentation [here](./configuration.md#subscribing-to-catalog-errors) for how to subscribe and log these error events. +sufficient information for a reader to find the causes for errors. See the [configuration documentation](./configuration.md#subscribing-to-catalog-errors) for how to subscribe and log these error events. Since these events are typically not easily found by end users, this can mainly be a useful tool for Backstage operators who want to debug problems either with statically registered entities that are under their control, or to help end users find From f304e99204b0c8a211f4a616daf4baec2c469974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 19 Jun 2024 16:34:44 +0200 Subject: [PATCH 133/860] Update plugins/catalog-backend-module-logs/package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/catalog-backend-module-logs/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index 879ed3176a..e8ed120872 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -3,7 +3,9 @@ "version": "0.0.0", "description": "A module that subscribes to catalog releated events and logs them.", "backstage": { - "role": "backend-plugin-module" + "role": "backend-plugin-module", + "pluginId": "catalog", + "pluginPackage": "@backstage/plugin-catalog-backend" }, "publishConfig": { "access": "public", From 2a2de3984e6e261a0d0965595bbed5fd69a4bd60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 19 Jun 2024 16:34:49 +0200 Subject: [PATCH 134/860] Update plugins/catalog-backend-module-logs/package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/catalog-backend-module-logs/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index e8ed120872..858f7ec198 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -33,7 +33,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-events-node": "workspace:^" From 066cc7143ef4c51f8baff98b914ab2c2cdb5ff95 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 11:09:50 -0400 Subject: [PATCH 135/860] remove verbage to docs that exist elsewhere Signed-off-by: Christopher Diaz --- docs/features/software-catalog/life-of-an-entity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index d333b90565..1489688720 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -204,7 +204,7 @@ tool for Backstage operators who want to debug problems either with statically registered entities that are under their control, or to help end users find problems. -> Prior to Backstage version v1.26.0 and `@backstage/plugin-catalog-backend` v1.21.9 catalog errors were logged by default. See the docs below on how to enable these logs and an example on how you can further customize how you ingest these errors. +> Prior to Backstage version v1.26.0 and `@backstage/plugin-catalog-backend` v1.21.9 catalog errors were logged by default. Second, for most classes of errors, the entity itself will contain a status field that describes the problem. The contents of this field is shown at the top From 16589947aa9bdc95fba049d17f3cecc50b869e78 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 11:12:30 -0400 Subject: [PATCH 136/860] remove duplicate module docs and point to backstage docs Signed-off-by: Christopher Diaz --- plugins/catalog-backend-module-logs/README.md | 37 ++----------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/plugins/catalog-backend-module-logs/README.md b/plugins/catalog-backend-module-logs/README.md index 7e20a0161b..1771dbe02c 100644 --- a/plugins/catalog-backend-module-logs/README.md +++ b/plugins/catalog-backend-module-logs/README.md @@ -2,38 +2,7 @@ A module that subscribes to catalog related events and logs them. -Catalog errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them. +## Getting started -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 -yarn --cwd packages/backend add @backstage/plugin-events-node -``` - -Now you can install the events backend plugin in your backend. - -Install the catalog logs module. - -```ts -# From your Backstage root directory -yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs -``` - -Add the module to your backend. - -```ts title="packages/backend/src/index.ts" -backend.add(import('@backstage/plugin-events-backend/alpha')); -``` - -Now install the catalog logs module. - -```ts title="packages/backend/src/index.ts" -backend.add(import('@backstage/plugin-catalog-backend-module-logs')); -``` - -You should now see logs as the catalog emits events. Example: - -``` -[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml -``` +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. From d3f280b51fa7f0c0283cfbd02a7efad73f729aa9 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 11:21:41 -0400 Subject: [PATCH 137/860] remove un-needed line in docs and update changeset to use a link Signed-off-by: Christopher Diaz --- .changeset/ten-pots-walk.md | 35 ++----------------- .../software-catalog/configuration.md | 2 +- 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/.changeset/ten-pots-walk.md b/.changeset/ten-pots-walk.md index e8f68afbe0..cf540fd0e2 100644 --- a/.changeset/ten-pots-walk.md +++ b/.changeset/ten-pots-walk.md @@ -4,36 +4,5 @@ Creates a new module to make logging catalog errors simple. This module subscribes to catalog events and logs them. -Catalog errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them. - -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 -yarn --cwd packages/backend add @backstage/plugin-events-node -``` - -Now you can install the events backend plugin in your backend. - -```ts title="packages/backend/src/index.ts" -backend.add(import('@backstage/plugin-events-backend/alpha')); -``` - -Install the catalog logs module. - -```ts -# From your Backstage root directory -yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs -``` - -Add the module to your backend. - -```ts title="packages/backend/src/index.ts" -backend.add(import('@backstage/plugin-catalog-backend-module-logs')); -``` - -You should now see logs as the catalog emits events. Example: - -``` -[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml -``` +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/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 9805eb06dd..3bbbfd6716 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -222,7 +222,7 @@ You should now see logs as the catalog emits events. Example: ### Custom Error Handling -If you wish to handle catalog errors with logic the following should help you get started. +If you wish to handle catalog errors with specific logic different from logging the errors the following should help you get started. For example, you may wish to send a notification or create a ticket for someone to investigate. Create a backend module that subscribes to the catalog error events. The topic is `experimental.catalog.errors`. From e61267416795b27e6530a40686c1459ac88b272f Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 11:24:03 -0400 Subject: [PATCH 138/860] update lockfile Signed-off-by: Christopher Diaz --- yarn.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 6c298b9c89..7d440ea43f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5444,7 +5444,6 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-backend-module-logs@workspace:plugins/catalog-backend-module-logs" dependencies: - "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" From 26bd7a7a92971f9157f5a04fc537aed232414925 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 12:16:26 -0400 Subject: [PATCH 139/860] try to update api docs Signed-off-by: Christopher Diaz --- plugins/catalog-backend-module-logs/api-report.md | 2 +- plugins/catalog-backend-module-logs/src/module.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-backend-module-logs/api-report.md b/plugins/catalog-backend-module-logs/api-report.md index 7dd45e6119..bb08280566 100644 --- a/plugins/catalog-backend-module-logs/api-report.md +++ b/plugins/catalog-backend-module-logs/api-report.md @@ -5,7 +5,7 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; -// @public (undocumented) +// @public const catalogModuleLogs: () => BackendFeature; export default catalogModuleLogs; ``` diff --git a/plugins/catalog-backend-module-logs/src/module.ts b/plugins/catalog-backend-module-logs/src/module.ts index 54fc428cdf..bdc916e958 100644 --- a/plugins/catalog-backend-module-logs/src/module.ts +++ b/plugins/catalog-backend-module-logs/src/module.ts @@ -31,7 +31,12 @@ interface EventsParamsWithPayload extends EventParams { eventPayload: EventsPayload; } -/** @public */ +/** + * A catalog module that logs catalog errors using the logger service. + * + * @packageDocumentation + * @public + */ export const catalogModuleLogs = createBackendModule({ pluginId: 'catalog', moduleId: 'logs', From c057720a67cd0b34a322de0d492091d42a81a94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 19 Jun 2024 19:36:51 +0200 Subject: [PATCH 140/860] api report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/catalog-backend-module-logs/api-report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-backend-module-logs/api-report.md b/plugins/catalog-backend-module-logs/api-report.md index bb08280566..0be2197c9a 100644 --- a/plugins/catalog-backend-module-logs/api-report.md +++ b/plugins/catalog-backend-module-logs/api-report.md @@ -3,9 +3,9 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { BackendFeature } from '@backstage/backend-plugin-api'; +import { BackendFeatureCompat } from '@backstage/backend-plugin-api'; // @public -const catalogModuleLogs: () => BackendFeature; +const catalogModuleLogs: BackendFeatureCompat; export default catalogModuleLogs; ``` From bdcb2990b321d2fc1e9379f637e3e6ab97f20126 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 15:28:07 -0400 Subject: [PATCH 141/860] feat: support tag based policies Signed-off-by: Christopher Diaz --- .../src/actions/githubEnvironment.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts index 7f6f9f7fa3..e821ff0cd6 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts @@ -44,6 +44,7 @@ export function createGithubEnvironmentAction(options: { custom_branch_policies: boolean; }; customBranchPolicyNames?: string[]; + customTagPolicyNames?: string[]; environmentVariables?: { [key: string]: string }; secrets?: { [key: string]: string }; token?: string; @@ -94,6 +95,16 @@ export function createGithubEnvironmentAction(options: { type: 'string', }, }, + customTagPolicyNames: { + title: 'Custom Tag Policy Name', + description: `The name pattern that tags must match in order to deploy to the environment. + + Wildcard characters will not match /. For example, to match tags that begin with release/ and contain an additional single slash, use release/*/*. For more information about pattern matching syntax, see the Ruby File.fnmatch documentation.`, + type: 'array', + items: { + type: 'string', + }, + }, environmentVariables: { title: 'Environment Variables', description: `Environment variables attached to the deployment environment`, @@ -118,6 +129,7 @@ export function createGithubEnvironmentAction(options: { name, deploymentBranchPolicy, customBranchPolicyNames, + customTagPolicyNames, environmentVariables, secrets, token: providedToken, @@ -153,6 +165,19 @@ export function createGithubEnvironmentAction(options: { await client.rest.repos.createDeploymentBranchPolicy({ owner: owner, repo: repo, + type: 'branch', + environment_name: name, + name: item, + }); + } + } + + if (customTagPolicyNames) { + for (const item of customTagPolicyNames) { + await client.rest.repos.createDeploymentBranchPolicy({ + owner: owner, + repo: repo, + type: 'tag', environment_name: name, name: item, }); From 70c4b3625db012293b6f3c638e4f60eb61ecc5a5 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Wed, 19 Jun 2024 15:32:42 -0400 Subject: [PATCH 142/860] feat: support tag based policies Signed-off-by: Christopher Diaz --- .changeset/short-flowers-cry.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/short-flowers-cry.md diff --git a/.changeset/short-flowers-cry.md b/.changeset/short-flowers-cry.md new file mode 100644 index 0000000000..bf2c354465 --- /dev/null +++ b/.changeset/short-flowers-cry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': minor +--- + +Adds support for custom tag policies when creating GitHub environments. From 3bf0697eb80eb0a78c654c896587e03e678e510e Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Thu, 20 Jun 2024 10:23:18 +0200 Subject: [PATCH 143/860] 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 8dc15aae58a74fcca6a978b41b13b1bace21b8e8 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:19:40 +0200 Subject: [PATCH 144/860] backend-app-api: httpRouter add healthCheckConfig Signed-off-by: Vincenzo Scamporlino --- .../httpRouter/httpRouterServiceFactory.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts index 58c074f985..2fd6923125 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts @@ -162,6 +162,18 @@ describe('httpRouterFactory', () => { }); }); + it('should always allow the healthcheck endpoint', async () => { + const { server } = await startTestBackend({ + features: [pluginSubject, ...defaultServices], + }); + + await expect( + request(server).get('/api/test/healthcheck'), + ).resolves.toMatchObject({ + status: 200, + }); + }); + it('should not block unauthenticated requests if default policy is disabled', async () => { const { server } = await startTestBackend({ features: [ From 8bbbc314f1d0693f616015301a0b06ba418e7ca5 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:20:10 +0200 Subject: [PATCH 145/860] backend-app-api: healthcheck middleware Signed-off-by: Vincenzo Scamporlino --- .../httpRouter/createHealthcheck.test.ts | 33 ++++++++++++++++++ .../httpRouter/createHealthcheck.ts | 34 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts create mode 100644 packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts new file mode 100644 index 0000000000..c23200a823 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts @@ -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 express from 'express'; +import request from 'supertest'; +import { createHealthcheck } from './createHealthcheck'; + +describe('createHealthcheck', () => { + it('should return a router with a healthcheck endpoint', async () => { + const hc = createHealthcheck(); + const app = express().use(hc.router); + + let response = await request(app).get('/healthcheck').expect(200); + expect(response.body).toEqual({ status: 'ok' }); + + hc.addHandler(async () => ({ allgood: true })); + response = await request(app).get('/healthcheck').expect(200); + expect(response.body).toEqual({ allgood: true }); + }); +}); diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts new file mode 100644 index 0000000000..f177822a17 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts @@ -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 { Request, Response } from 'express'; +import Router from 'express-promise-router'; + +export function createHealthcheck() { + const router = Router(); + let handler = () => Promise.resolve({ status: 'ok' }); + + router.get('/healthcheck', async (_request: Request, response: Response) => { + const status = await handler(); + response.json(status); + }); + + return { + router, + addHandler: (newHandler: () => Promise) => { + handler = newHandler; + }, + }; +} From 14e982e8d3fa699196c94d392484f581cd426d5d Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:34:55 +0200 Subject: [PATCH 146/860] backend-plugin-api: export healthCheckConfig fn Signed-off-by: Vincenzo Scamporlino --- .../src/services/definitions/HttpRouterService.ts | 7 +++++++ .../backend-plugin-api/src/services/definitions/index.ts | 1 + .../backend-test-utils/src/next/services/mockServices.ts | 1 + 3 files changed, 9 insertions(+) diff --git a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts index 92f7e950f9..2cb5c74649 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts @@ -26,6 +26,11 @@ export interface HttpRouterServiceAuthPolicy { allow: 'unauthenticated' | 'user-cookie'; } +/** @public */ +export interface HttpRouterHealthCheckConfig { + handler: () => Promise; +} + /** * Allows plugins to register HTTP routes. * @@ -40,6 +45,8 @@ export interface HttpRouterService { */ use(handler: Handler): void; + healthCheckConfig(healthCheckOptions: HttpRouterHealthCheckConfig): void; + /** * Adds an auth policy to the router. This is used to allow unauthenticated or * cookie based access to parts of a plugin's API. diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index 6f30c5f980..57cfd404c1 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -35,6 +35,7 @@ export type { DiscoveryService } from './DiscoveryService'; export type { HttpRouterService, HttpRouterServiceAuthPolicy, + HttpRouterHealthCheckConfig, } from './HttpRouterService'; export type { HttpAuthService } from './HttpAuthService'; export type { diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 24571b634c..379e9473ca 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -348,6 +348,7 @@ export namespace mockServices { export const factory = httpRouterServiceFactory; export const mock = simpleMock(coreServices.httpRouter, () => ({ use: jest.fn(), + healthCheckConfig: jest.fn(), addAuthPolicy: jest.fn(), })); } From 53ced701dd6f68b956c3c311da9d674befb0b64a Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 11:41:37 +0200 Subject: [PATCH 147/860] healthcheck changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/bright-panthers-leave.md diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md new file mode 100644 index 0000000000..133760cadd --- /dev/null +++ b/.changeset/bright-panthers-leave.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/backend-test-utils': patch +'@backstage/backend-app-api': patch +--- + +Added a default `/healthcheck` endpoint to the HTTP Router. From 8d4735767dbada61ac99000ec4e126f5d090c292 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 15:17:26 +0200 Subject: [PATCH 148/860] backend-app-api: move healthchecks to healthService Signed-off-by: Vincenzo Scamporlino --- .../health/createHealthRouter.test.ts | 81 +++++++++++++++++++ .../health/createHealthRouter.ts | 46 +++++++++++ .../health/healthServiceFactory.ts | 34 ++++++++ .../services/implementations/health/index.ts | 17 ++++ .../createHealthcheck.test.ts | 0 .../createHealthcheck.ts | 0 .../src/services/definitions/HealthService.ts | 20 +++++ .../services/definitions/HttpRouterService.ts | 5 -- .../src/services/definitions/coreServices.ts | 7 ++ .../src/services/definitions/index.ts | 2 +- .../src/next/services/mockServices.ts | 1 - 11 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts create mode 100644 packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts create mode 100644 packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts create mode 100644 packages/backend-app-api/src/services/implementations/health/index.ts rename packages/backend-app-api/src/services/implementations/{httpRouter => rootHttpRouter}/createHealthcheck.test.ts (100%) rename packages/backend-app-api/src/services/implementations/{httpRouter => rootHttpRouter}/createHealthcheck.ts (100%) create mode 100644 packages/backend-plugin-api/src/services/definitions/HealthService.ts diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts new file mode 100644 index 0000000000..f8c51ee08d --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { mockServices } from '@backstage/backend-test-utils'; +import request from 'supertest'; +import { createHealthRouter } from './createHealthRouter'; +import express from 'express'; + +describe('createHealthRouter', () => { + describe('readiness', () => { + it(`should return a 500 response if the server hasn't started yet`, async () => { + const hc = createHealthRouter({ + lifecycle: mockServices.rootLifecycle.mock(), + }); + const app = express().use(hc); + + const response = await request(app).get('/v1/readiness'); + expect(response.status).toBe(500); + }); + + it('should return 200 if the server has started', async () => { + const lifecycle = mockServices.rootLifecycle.mock(); + let mockServerStartedFn = () => {}; + lifecycle.addStartupHook.mockImplementation( + fn => (mockServerStartedFn = fn), + ); + + const hc = createHealthRouter({ lifecycle }); + const app = express().use(hc); + + mockServerStartedFn(); + const response = await request(app).get('/v1/readiness').expect(200); + expect(response.body).toEqual({ status: 'ok' }); + }); + + it(`should return a 500 response if the server has stopped`, async () => { + const lifecycle = mockServices.rootLifecycle.mock(); + let mockServerStartedFn = () => {}; + let mockServerStoppedFn = () => {}; + lifecycle.addStartupHook.mockImplementation( + fn => (mockServerStartedFn = fn), + ); + lifecycle.addShutdownHook.mockImplementation( + fn => (mockServerStoppedFn = fn), + ); + + const hc = createHealthRouter({ lifecycle }); + const app = express().use(hc); + + mockServerStartedFn(); + mockServerStoppedFn(); + const response = await request(app).get('/v1/readiness'); + expect(response.status).toBe(500); + }); + }); + + describe('liveness', () => { + it('should return 200 if the server has started', async () => { + const lifecycle = mockServices.rootLifecycle.mock(); + + const hc = createHealthRouter({ lifecycle }); + const app = express().use(hc); + + const response = await request(app).get('/v1/liveness').expect(200); + expect(response.body).toEqual({ status: 'ok' }); + }); + }); +}); diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts new file mode 100644 index 0000000000..f2ff2ecd73 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts @@ -0,0 +1,46 @@ +/* + * 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 Router from 'express-promise-router'; +import { Request, Response } from 'express'; +import { RootLifecycleService } from '@backstage/backend-plugin-api'; + +export function createHealthRouter(options: { + lifecycle: RootLifecycleService; +}) { + const router = Router(); + + let isRunning = false; + options.lifecycle.addStartupHook(() => { + isRunning = true; + }); + options.lifecycle.addShutdownHook(() => { + isRunning = false; + }); + + router.get('/v1/readiness', async (_request: Request, response: Response) => { + if (!isRunning) { + throw new Error('Backend has not started yet'); + } + response.json({ status: 'ok' }); + }); + + router.get('/v1/liveness', async (_request: Request, response: Response) => { + response.json({ status: 'ok' }); + }); + + return router; +} diff --git a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts new file mode 100644 index 0000000000..831f4fa6e8 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts @@ -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 { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { createHealthRouter } from './createHealthRouter'; + +export const healthServiceFactory = createServiceFactory({ + service: coreServices.health, + deps: { + rootHttpRouter: coreServices.rootHttpRouter, + lifecycle: coreServices.rootLifecycle, + }, + async factory({ lifecycle, rootHttpRouter }) { + rootHttpRouter.use('.backstage/health', createHealthRouter({ lifecycle })); + + return {}; + }, +}); diff --git a/packages/backend-app-api/src/services/implementations/health/index.ts b/packages/backend-app-api/src/services/implementations/health/index.ts new file mode 100644 index 0000000000..4aeb4b7979 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/health/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export { healthServiceFactory } from './healthServiceFactory'; diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts similarity index 100% rename from packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.test.ts rename to packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts similarity index 100% rename from packages/backend-app-api/src/services/implementations/httpRouter/createHealthcheck.ts rename to packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts diff --git a/packages/backend-plugin-api/src/services/definitions/HealthService.ts b/packages/backend-plugin-api/src/services/definitions/HealthService.ts new file mode 100644 index 0000000000..d04a8a6133 --- /dev/null +++ b/packages/backend-plugin-api/src/services/definitions/HealthService.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + * @public + */ +export interface HealthService {} diff --git a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts index 2cb5c74649..30c4fb31c8 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts @@ -26,11 +26,6 @@ export interface HttpRouterServiceAuthPolicy { allow: 'unauthenticated' | 'user-cookie'; } -/** @public */ -export interface HttpRouterHealthCheckConfig { - handler: () => Promise; -} - /** * Allows plugins to register HTTP routes. * diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts index b0518fb9d4..36ec0151c5 100644 --- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts +++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts @@ -102,6 +102,13 @@ export namespace coreServices { import('./DiscoveryService').DiscoveryService >({ id: 'core.discovery' }); + /** + * The service reference for the plugin scoped {@link RootHealthService}. + */ + export const health = createServiceRef< + import('./RootHealthService').RootHealthService + >({ id: 'core.health', scope: 'root' }); + /** * Authentication of HTTP requests. * diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index 57cfd404c1..af0d991f58 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -32,10 +32,10 @@ export type { export type { RootConfigService } from './RootConfigService'; export type { DatabaseService } from './DatabaseService'; export type { DiscoveryService } from './DiscoveryService'; +export type { HealthService } from './HealthService'; export type { HttpRouterService, HttpRouterServiceAuthPolicy, - HttpRouterHealthCheckConfig, } from './HttpRouterService'; export type { HttpAuthService } from './HttpAuthService'; export type { diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 379e9473ca..24571b634c 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -348,7 +348,6 @@ export namespace mockServices { export const factory = httpRouterServiceFactory; export const mock = simpleMock(coreServices.httpRouter, () => ({ use: jest.fn(), - healthCheckConfig: jest.fn(), addAuthPolicy: jest.fn(), })); } From b26877ffc50329ce93bd9a7b3d6f016a6f8cd7c6 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 15:18:16 +0200 Subject: [PATCH 149/860] backend-defaults: add healthservice Signed-off-by: Vincenzo Scamporlino --- packages/backend-defaults/src/CreateBackend.ts | 2 ++ .../src/services/definitions/HttpRouterService.ts | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 9b3fa5d649..453c5fe592 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -24,6 +24,7 @@ import { authServiceFactory } from '@backstage/backend-defaults/auth'; import { cacheServiceFactory } from '@backstage/backend-defaults/cache'; import { databaseServiceFactory } from '@backstage/backend-defaults/database'; import { discoveryServiceFactory } from '@backstage/backend-defaults/discovery'; +import { rootHealthServiceFactory } from './entrypoints/rootHealth'; import { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; @@ -58,6 +59,7 @@ export const defaultServiceFactories = [ userInfoServiceFactory(), urlReaderServiceFactory(), eventsServiceFactory(), + rootHealthServiceFactory(), ]; /** diff --git a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts index 30c4fb31c8..92f7e950f9 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts @@ -40,8 +40,6 @@ export interface HttpRouterService { */ use(handler: Handler): void; - healthCheckConfig(healthCheckOptions: HttpRouterHealthCheckConfig): void; - /** * Adds an auth policy to the router. This is used to allow unauthenticated or * cookie based access to parts of a plugin's API. From 1ce0bb70605a3124af959e83993a24f47b58e26e Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 15:20:44 +0200 Subject: [PATCH 150/860] tweak changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md index 133760cadd..acd9764fe6 100644 --- a/.changeset/bright-panthers-leave.md +++ b/.changeset/bright-panthers-leave.md @@ -1,7 +1,7 @@ --- '@backstage/backend-plugin-api': patch -'@backstage/backend-test-utils': patch +'@backstage/backend-defaults': patch '@backstage/backend-app-api': patch --- -Added a default `/healthcheck` endpoint to the HTTP Router. +Added a new health service which adds new endpoints for health checks. From 0717aaeda6098f7f3e72f7bb721ec8e38f7062d1 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 19:18:06 +0200 Subject: [PATCH 151/860] backend-app-api: remove test Signed-off-by: Vincenzo Scamporlino --- .../httpRouter/httpRouterServiceFactory.test.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts index 2fd6923125..58c074f985 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts @@ -162,18 +162,6 @@ describe('httpRouterFactory', () => { }); }); - it('should always allow the healthcheck endpoint', async () => { - const { server } = await startTestBackend({ - features: [pluginSubject, ...defaultServices], - }); - - await expect( - request(server).get('/api/test/healthcheck'), - ).resolves.toMatchObject({ - status: 200, - }); - }); - it('should not block unauthenticated requests if default policy is disabled', async () => { const { server } = await startTestBackend({ features: [ From 49b489088cd9f7e262949c21599001c918349dd6 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 17 May 2024 20:20:44 +0200 Subject: [PATCH 152/860] backend-app-api: mark healthServiceFactory as public Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/api-report.md | 4 ++++ .../services/implementations/health/healthServiceFactory.ts | 3 +++ 2 files changed, 7 insertions(+) diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 7518f8e2cc..a18f027273 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -18,6 +18,7 @@ import { ErrorRequestHandler } from 'express'; import { Express as Express_2 } from 'express'; import { Format } from 'logform'; import { Handler } from 'express'; +import { HealthService } from '@backstage/backend-plugin-api'; import { HelmetOptions } from 'helmet'; import * as http from 'http'; import { HttpAuthService } from '@backstage/backend-plugin-api'; @@ -126,6 +127,9 @@ export const discoveryServiceFactory: () => ServiceFactory< // @public @deprecated (undocumented) export type ExtendedHttpServer = ExtendedHttpServer_2; +// @public (undocumented) +export const healthServiceFactory: () => ServiceFactory; + // @public @deprecated export class HostDiscovery implements DiscoveryService { static fromConfig( diff --git a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts index 831f4fa6e8..b79ba34a87 100644 --- a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts @@ -20,6 +20,9 @@ import { } from '@backstage/backend-plugin-api'; import { createHealthRouter } from './createHealthRouter'; +/** + * @public + */ export const healthServiceFactory = createServiceFactory({ service: coreServices.health, deps: { From a38ffb2cb3a72d80027e3293efa74fbd13212a6a Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 13:33:38 +0200 Subject: [PATCH 153/860] backend-test-utils: mock health service Signed-off-by: Vincenzo Scamporlino --- .../backend-test-utils/src/next/services/mockServices.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 24571b634c..22496bd6e1 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -24,6 +24,7 @@ import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; +import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; @@ -383,6 +384,14 @@ export namespace mockServices { })); } + export namespace rootHealth { + export const factory = rootHealthServiceFactory; + export const mock = simpleMock(coreServices.health, () => ({ + getLiveness: jest.fn(), + getReadiness: jest.fn(), + })); + } + export namespace rootLifecycle { export const factory = rootLifecycleServiceFactory; export const mock = simpleMock(coreServices.rootLifecycle, () => ({ From 972896d192834f5ff2d0c115bb6513f758a13829 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 13:33:54 +0200 Subject: [PATCH 154/860] backend-app-api: clean up Signed-off-by: Vincenzo Scamporlino --- .../rootHttpRouter/createHealthcheck.test.ts | 33 ------------------ .../rootHttpRouter/createHealthcheck.ts | 34 ------------------- 2 files changed, 67 deletions(-) delete mode 100644 packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts delete mode 100644 packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts deleted file mode 100644 index c23200a823..0000000000 --- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 express from 'express'; -import request from 'supertest'; -import { createHealthcheck } from './createHealthcheck'; - -describe('createHealthcheck', () => { - it('should return a router with a healthcheck endpoint', async () => { - const hc = createHealthcheck(); - const app = express().use(hc.router); - - let response = await request(app).get('/healthcheck').expect(200); - expect(response.body).toEqual({ status: 'ok' }); - - hc.addHandler(async () => ({ allgood: true })); - response = await request(app).get('/healthcheck').expect(200); - expect(response.body).toEqual({ allgood: true }); - }); -}); diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts deleted file mode 100644 index f177822a17..0000000000 --- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/createHealthcheck.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 { Request, Response } from 'express'; -import Router from 'express-promise-router'; - -export function createHealthcheck() { - const router = Router(); - let handler = () => Promise.resolve({ status: 'ok' }); - - router.get('/healthcheck', async (_request: Request, response: Response) => { - const status = await handler(); - response.json(status); - }); - - return { - router, - addHandler: (newHandler: () => Promise) => { - handler = newHandler; - }, - }; -} From 652da2e3e342994f72639754cafba858dc1d0a94 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 13:45:41 +0200 Subject: [PATCH 155/860] docs: add health service Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/01-index.md | 1 + docs/backend-system/core-services/health.md | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 docs/backend-system/core-services/health.md diff --git a/docs/backend-system/core-services/01-index.md b/docs/backend-system/core-services/01-index.md index 04d2e57ae8..63324292c1 100644 --- a/docs/backend-system/core-services/01-index.md +++ b/docs/backend-system/core-services/01-index.md @@ -20,6 +20,7 @@ import { coreServices } from '@backstage/backend-plugin-api'; - [Cache Service](./cache.md) - Key-value store for caching data. - [Database Service](./database.md) - Database access and management via [knex](https://knexjs.org/). - [Discovery Service](./discovery.md) - Service discovery for inter-plugin communication. +- [Health Service](./health.md) - Health check endpoints for the backend. - [Http Auth Service](./http-auth.md) - Authentication of HTTP requests. - [Http Router Service](./http-router.md) - HTTP route registration for plugins. - [Identity Service](./identity.md) - Deprecated user authentication service, use the [Auth Service](./auth.md) instead. diff --git a/docs/backend-system/core-services/health.md b/docs/backend-system/core-services/health.md new file mode 100644 index 0000000000..9a69891624 --- /dev/null +++ b/docs/backend-system/core-services/health.md @@ -0,0 +1,39 @@ +--- +id: health +title: Heath Service +sidebar_label: Health +description: Documentation for the Health service +--- + +The Health service provides some health check endpoints for the plugins. By default, it attaches `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints to the backend server, which return a JSON object with the status of the backend services. + +## Configuring the service + +The following example is how you can override the health service to add custom endpoints. + +```ts +import { coreServices } from '@backstage/backend-plugin-api'; +import { WinstonLogger } from '@backstage/backend-app-api'; + +const backend = createBackend(); + +backend.add( + createServiceFactory({ + service: coreServices.health, + deps: { + rootHttpRouter: coreServices.rootHttpRouter, + }, + async factory({ rootHttpRouter }) { + rootHttpRouter.get('.backstage/health/v1/readiness', async (req, res) => { + res.json({ status: 'ok' }); + }); + + rootHttpRouter.get('.backstage/health/v1/liveness', async (req, res) => { + res.json({ status: 'ok' }); + }); + + return {}; + }, + }), +); +``` From 78fdc5a39f613a50f6a024b68a9abb1201396d78 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 14:11:33 +0200 Subject: [PATCH 156/860] health service api report Signed-off-by: Vincenzo Scamporlino --- packages/backend-plugin-api/api-report.md | 4 ++++ packages/backend-test-utils/api-report.md | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 258cdefe1b..5e02ad1787 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -194,6 +194,7 @@ export namespace coreServices { const rootConfig: ServiceRef; const database: ServiceRef; const discovery: ServiceRef; + const health: ServiceRef; const httpAuth: ServiceRef; const httpRouter: ServiceRef; const lifecycle: ServiceRef; @@ -333,6 +334,9 @@ export type ExtensionPoint = { // @public @deprecated (undocumented) export type ExtensionPointConfig = CreateExtensionPointOptions; +// @public (undocumented) +export interface HealthService {} + // @public export interface HttpAuthService { credentials( diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 019d398ea6..07b393b653 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -21,6 +21,7 @@ import { DiscoveryService } from '@backstage/backend-plugin-api'; import { EventsService } from '@backstage/plugin-events-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { HealthService } 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'; @@ -199,6 +200,15 @@ export namespace mockServices { partialImpl?: Partial | undefined, ) => ServiceMock; } + // (undocumented) + export namespace health { + const // (undocumented) + factory: () => ServiceFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; + } export function httpAuth(options?: { pluginId?: string; defaultCredentials?: BackstageCredentials; From fce7887109d2741e896b0c2d25303999db42760c Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 3 Jun 2024 14:18:11 +0200 Subject: [PATCH 157/860] backend-test-utils: health service mock changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/serious-kings-trade.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/serious-kings-trade.md diff --git a/.changeset/serious-kings-trade.md b/.changeset/serious-kings-trade.md new file mode 100644 index 0000000000..c07e92b88a --- /dev/null +++ b/.changeset/serious-kings-trade.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Added mock for health service in `mockServices`. From 918b397763b17f70bab8494bd7b87ddeb084d1b2 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Wed, 5 Jun 2024 13:27:10 +0200 Subject: [PATCH 158/860] backend-defaults: move over health service Signed-off-by: Vincenzo Scamporlino --- .../health/createHealthRouter.ts | 46 -------------- .../health/healthServiceFactory.ts | 37 ----------- .../backend-defaults/api-report-health.md | 13 ++++ packages/backend-defaults/package.json | 4 ++ .../health/healthServiceFactory.test.ts} | 53 ++++++++-------- .../health/healthServiceFactory.ts | 63 +++++++++++++++++++ .../src/entrypoints}/health/index.ts | 0 7 files changed, 107 insertions(+), 109 deletions(-) delete mode 100644 packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts delete mode 100644 packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts create mode 100644 packages/backend-defaults/api-report-health.md rename packages/{backend-app-api/src/services/implementations/health/createHealthRouter.test.ts => backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts} (63%) create mode 100644 packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts rename packages/{backend-app-api/src/services/implementations => backend-defaults/src/entrypoints}/health/index.ts (100%) diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts b/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts deleted file mode 100644 index f2ff2ecd73..0000000000 --- a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 Router from 'express-promise-router'; -import { Request, Response } from 'express'; -import { RootLifecycleService } from '@backstage/backend-plugin-api'; - -export function createHealthRouter(options: { - lifecycle: RootLifecycleService; -}) { - const router = Router(); - - let isRunning = false; - options.lifecycle.addStartupHook(() => { - isRunning = true; - }); - options.lifecycle.addShutdownHook(() => { - isRunning = false; - }); - - router.get('/v1/readiness', async (_request: Request, response: Response) => { - if (!isRunning) { - throw new Error('Backend has not started yet'); - } - response.json({ status: 'ok' }); - }); - - router.get('/v1/liveness', async (_request: Request, response: Response) => { - response.json({ status: 'ok' }); - }); - - return router; -} diff --git a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts b/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts deleted file mode 100644 index b79ba34a87..0000000000 --- a/packages/backend-app-api/src/services/implementations/health/healthServiceFactory.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { createHealthRouter } from './createHealthRouter'; - -/** - * @public - */ -export const healthServiceFactory = createServiceFactory({ - service: coreServices.health, - deps: { - rootHttpRouter: coreServices.rootHttpRouter, - lifecycle: coreServices.rootLifecycle, - }, - async factory({ lifecycle, rootHttpRouter }) { - rootHttpRouter.use('.backstage/health', createHealthRouter({ lifecycle })); - - return {}; - }, -}); diff --git a/packages/backend-defaults/api-report-health.md b/packages/backend-defaults/api-report-health.md new file mode 100644 index 0000000000..795bdaac78 --- /dev/null +++ b/packages/backend-defaults/api-report-health.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { HealthService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public (undocumented) +export const healthServiceFactory: () => ServiceFactory; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 4c34c7f317..c29d973997 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -24,6 +24,7 @@ "./cache": "./src/entrypoints/cache/index.ts", "./database": "./src/entrypoints/database/index.ts", "./discovery": "./src/entrypoints/discovery/index.ts", + "./health": "./src/entrypoints/health/index.ts", "./httpAuth": "./src/entrypoints/httpAuth/index.ts", "./httpRouter": "./src/entrypoints/httpRouter/index.ts", "./lifecycle": "./src/entrypoints/lifecycle/index.ts", @@ -54,6 +55,9 @@ "discovery": [ "src/entrypoints/discovery/index.ts" ], + "health": [ + "src/entrypoints/health/index.ts" + ], "httpAuth": [ "src/entrypoints/httpAuth/index.ts" ], diff --git a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts similarity index 63% rename from packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts rename to packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts index f8c51ee08d..40a41d74f5 100644 --- a/packages/backend-app-api/src/services/implementations/health/createHealthRouter.test.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts @@ -1,3 +1,6 @@ +import { mockServices } from '@backstage/backend-test-utils'; +import { DefaultHealthService } from './healthServiceFactory'; + /* * Copyright 2024 The Backstage Authors * @@ -13,22 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { mockServices } from '@backstage/backend-test-utils'; -import request from 'supertest'; -import { createHealthRouter } from './createHealthRouter'; -import express from 'express'; - -describe('createHealthRouter', () => { +describe('DefaultHealthService', () => { describe('readiness', () => { it(`should return a 500 response if the server hasn't started yet`, async () => { - const hc = createHealthRouter({ + const service = new DefaultHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); - const app = express().use(hc); - - const response = await request(app).get('/v1/readiness'); - expect(response.status).toBe(500); + await expect(service.getReadiness()).resolves.toEqual({ status: 503 }); }); it('should return 200 if the server has started', async () => { @@ -38,12 +32,16 @@ describe('createHealthRouter', () => { fn => (mockServerStartedFn = fn), ); - const hc = createHealthRouter({ lifecycle }); - const app = express().use(hc); + const service = new DefaultHealthService({ + lifecycle: mockServices.rootLifecycle.mock(), + }); mockServerStartedFn(); - const response = await request(app).get('/v1/readiness').expect(200); - expect(response.body).toEqual({ status: 'ok' }); + + await expect(service.getReadiness()).resolves.toEqual({ + status: 200, + payload: { status: 'ok' }, + }); }); it(`should return a 500 response if the server has stopped`, async () => { @@ -57,25 +55,28 @@ describe('createHealthRouter', () => { fn => (mockServerStoppedFn = fn), ); - const hc = createHealthRouter({ lifecycle }); - const app = express().use(hc); + const service = new DefaultHealthService({ + lifecycle: mockServices.rootLifecycle.mock(), + }); mockServerStartedFn(); mockServerStoppedFn(); - const response = await request(app).get('/v1/readiness'); - expect(response.status).toBe(500); + await expect(service.getReadiness()).resolves.toEqual({ + status: 503, + }); }); }); describe('liveness', () => { it('should return 200 if the server has started', async () => { - const lifecycle = mockServices.rootLifecycle.mock(); + const service = new DefaultHealthService({ + lifecycle: mockServices.rootLifecycle.mock(), + }); - const hc = createHealthRouter({ lifecycle }); - const app = express().use(hc); - - const response = await request(app).get('/v1/liveness').expect(200); - expect(response.body).toEqual({ status: 'ok' }); + await expect(service.getLiveness()).resolves.toEqual({ + status: 200, + payload: { status: 'ok' }, + }); }); }); }); diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts new file mode 100644 index 0000000000..3f397ce29b --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts @@ -0,0 +1,63 @@ +import { + HealthService, + RootLifecycleService, + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; + +/* + * 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. + */ + +/** @internal */ +export class DefaultHealthService implements HealthService { + #isRunning = false; + + constructor(readonly options: { lifecycle: RootLifecycleService }) { + options.lifecycle.addStartupHook(() => { + this.#isRunning = true; + }); + options.lifecycle.addShutdownHook(() => { + this.#isRunning = false; + }); + } + + async getLiveness(): Promise<{ status: number; payload?: any }> { + return { status: 200, payload: { status: 'ok' } }; + } + async getReadiness(): Promise<{ status: number; payload?: any }> { + if (!this.#isRunning) { + return { + status: 503, + payload: { message: 'Backend has not started yet', status: 'error' }, + }; + } + + return { status: 200, payload: { status: 'ok' } }; + } +} + +/** + * @public + */ +export const healthServiceFactory = createServiceFactory({ + service: coreServices.health, + deps: { + lifecycle: coreServices.rootLifecycle, + }, + async factory({ lifecycle }) { + return new DefaultHealthService({ lifecycle }); + }, +}); diff --git a/packages/backend-app-api/src/services/implementations/health/index.ts b/packages/backend-defaults/src/entrypoints/health/index.ts similarity index 100% rename from packages/backend-app-api/src/services/implementations/health/index.ts rename to packages/backend-defaults/src/entrypoints/health/index.ts From 44f97c173bf9eefb3c281928b84aa1f80bc32375 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Wed, 5 Jun 2024 13:27:39 +0200 Subject: [PATCH 159/860] backend-app-api: flip logic of health service Signed-off-by: Vincenzo Scamporlino --- .../health/healthServiceFactory.test.ts | 14 ++++++- .../health/healthServiceFactory.ts | 1 + .../rootHttpRouter/createHealthRouter.ts | 42 +++++++++++++++++++ .../rootHttpRouterServiceFactory.ts | 9 +++- packages/backend-plugin-api/api-report.md | 13 +++++- .../src/services/definitions/HealthService.ts | 5 ++- .../src/next/services/mockServices.ts | 18 ++++---- 7 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts index 40a41d74f5..7e160cbd82 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts @@ -22,7 +22,13 @@ describe('DefaultHealthService', () => { const service = new DefaultHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); - await expect(service.getReadiness()).resolves.toEqual({ status: 503 }); + await expect(service.getReadiness()).resolves.toEqual({ + status: 503, + payload: { + message: 'Backend has not started yet', + status: 'error', + }, + }); }); it('should return 200 if the server has started', async () => { @@ -33,7 +39,7 @@ describe('DefaultHealthService', () => { ); const service = new DefaultHealthService({ - lifecycle: mockServices.rootLifecycle.mock(), + lifecycle, }); mockServerStartedFn(); @@ -63,6 +69,10 @@ describe('DefaultHealthService', () => { mockServerStoppedFn(); await expect(service.getReadiness()).resolves.toEqual({ status: 503, + payload: { + message: 'Backend has not started yet', + status: 'error', + }, }); }); }); diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts index 3f397ce29b..f68451df74 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts @@ -37,6 +37,7 @@ export class DefaultHealthService implements HealthService { async getLiveness(): Promise<{ status: number; payload?: any }> { return { status: 200, payload: { status: 'ok' } }; } + async getReadiness(): Promise<{ status: number; payload?: any }> { if (!this.#isRunning) { return { diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts new file mode 100644 index 0000000000..012a268e02 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -0,0 +1,42 @@ +import { HealthService } from '@backstage/backend-plugin-api'; + +/* + * 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 Router from 'express-promise-router'; +import { Request, Response } from 'express'; + +export function createHealthRouter(options: { health: HealthService }) { + const router = Router(); + + router.get( + '.backstage/health/v1/readiness', + async (_request: Request, response: Response) => { + const { status, payload } = await options.health.getReadiness(); + response.status(status).json(payload); + }, + ); + + router.get( + '.backstage/health/v1/liveness', + async (_request: Request, response: Response) => { + const { status, payload } = await options.health.getLiveness(); + response.status(status).json(payload); + }, + ); + + return router; +} diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index ea3dc42eb7..5f22cf5ced 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -29,6 +29,7 @@ import { readHttpServerOptions, } from './http'; import { DefaultRootHttpRouter } from './DefaultRootHttpRouter'; +import { createHealthRouter } from './createHealthRouter'; /** * @public @@ -41,6 +42,7 @@ export interface RootHttpRouterConfigureContext { config: RootConfigService; logger: LoggerService; lifecycle: LifecycleService; + healthRouter: RequestHandler; applyDefaults: () => void; } @@ -75,8 +77,9 @@ export const rootHttpRouterServiceFactory = createServiceFactory( config: coreServices.rootConfig, rootLogger: coreServices.rootLogger, lifecycle: coreServices.rootLifecycle, + health: coreServices.health, }, - async factory({ config, rootLogger, lifecycle }) { + async factory({ config, rootLogger, lifecycle, health }) { const { indexPath, configure = defaultConfigure } = options ?? {}; const logger = rootLogger.child({ service: 'rootHttpRouter' }); const app = express(); @@ -84,6 +87,8 @@ export const rootHttpRouterServiceFactory = createServiceFactory( const router = DefaultRootHttpRouter.create({ indexPath }); const middleware = MiddlewareFactory.create({ config, logger }); const routes = router.handler(); + + const healthRouter = createHealthRouter({ health }); const server = await createHttpServer( app, readHttpServerOptions(config.getOptionalConfig('backend')), @@ -98,11 +103,13 @@ export const rootHttpRouterServiceFactory = createServiceFactory( config, logger, lifecycle, + healthRouter, applyDefaults() { app.use(middleware.helmet()); app.use(middleware.cors()); app.use(middleware.compression()); app.use(middleware.logging()); + app.use(healthRouter); app.use(routes); app.use(middleware.notFound()); app.use(middleware.error()); diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 5e02ad1787..ee5aecd63b 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -335,7 +335,18 @@ export type ExtensionPoint = { export type ExtensionPointConfig = CreateExtensionPointOptions; // @public (undocumented) -export interface HealthService {} +export interface HealthService { + // (undocumented) + getLiveness(): Promise<{ + status: number; + payload?: any; + }>; + // (undocumented) + getReadiness(): Promise<{ + status: number; + payload?: any; + }>; +} // @public export interface HttpAuthService { diff --git a/packages/backend-plugin-api/src/services/definitions/HealthService.ts b/packages/backend-plugin-api/src/services/definitions/HealthService.ts index d04a8a6133..b2dc4f415e 100644 --- a/packages/backend-plugin-api/src/services/definitions/HealthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HealthService.ts @@ -17,4 +17,7 @@ /** * @public */ -export interface HealthService {} +export interface HealthService { + getLiveness(): Promise<{ status: number; payload?: any }>; + getReadiness(): Promise<{ status: number; payload?: any }>; +} diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 22496bd6e1..a59d053b95 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -20,11 +20,11 @@ import { HostDiscovery, discoveryServiceFactory, } from '@backstage/backend-defaults/discovery'; +import { healthServiceFactory } from '@backstage/backend-defaults/health'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; -import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; @@ -345,6 +345,14 @@ export namespace mockServices { })); } + export namespace health { + export const factory = healthServiceFactory; + export const mock = simpleMock(coreServices.health, () => ({ + getLiveness: jest.fn(), + getReadiness: jest.fn(), + })); + } + export namespace httpRouter { export const factory = httpRouterServiceFactory; export const mock = simpleMock(coreServices.httpRouter, () => ({ @@ -384,14 +392,6 @@ export namespace mockServices { })); } - export namespace rootHealth { - export const factory = rootHealthServiceFactory; - export const mock = simpleMock(coreServices.health, () => ({ - getLiveness: jest.fn(), - getReadiness: jest.fn(), - })); - } - export namespace rootLifecycle { export const factory = rootLifecycleServiceFactory; export const mock = simpleMock(coreServices.rootLifecycle, () => ({ From 506fc235567a02a8609c5859f3311cda393aaa04 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 13 Jun 2024 13:11:03 +0200 Subject: [PATCH 160/860] backend-defaults: fix notice Signed-off-by: Vincenzo Scamporlino --- .../src/entrypoints/health/healthServiceFactory.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts index f68451df74..652ad8758f 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts @@ -1,10 +1,3 @@ -import { - HealthService, - RootLifecycleService, - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; - /* * Copyright 2024 The Backstage Authors * @@ -21,6 +14,13 @@ import { * limitations under the License. */ +import { + HealthService, + RootLifecycleService, + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; + /** @internal */ export class DefaultHealthService implements HealthService { #isRunning = false; From 0c621514042da57665afc28336be9cfa03fe430d Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 13 Jun 2024 13:39:33 +0200 Subject: [PATCH 161/860] Rename HealthService to RootHealthService Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/01-index.md | 2 +- .../core-services/{health.md => root-health.md} | 0 packages/backend-defaults/package.json | 8 ++++---- packages/backend-defaults/src/CreateBackend.ts | 4 ++-- .../src/entrypoints/{health => rootHealth}/index.ts | 2 +- .../rootHealthServiceFactory.test.ts} | 12 ++++++------ .../rootHealthServiceFactory.ts} | 8 ++++---- .../entrypoints/rootHttpRouter/createHealthRouter.ts | 4 ++-- .../{HealthService.ts => RootHealthService.ts} | 8 +++++++- .../src/services/definitions/index.ts | 2 +- .../src/next/services/mockServices.ts | 6 +++--- 11 files changed, 31 insertions(+), 25 deletions(-) rename docs/backend-system/core-services/{health.md => root-health.md} (100%) rename packages/backend-defaults/src/entrypoints/{health => rootHealth}/index.ts (89%) rename packages/backend-defaults/src/entrypoints/{health/healthServiceFactory.test.ts => rootHealth/rootHealthServiceFactory.test.ts} (88%) rename packages/backend-defaults/src/entrypoints/{health/healthServiceFactory.ts => rootHealth/rootHealthServiceFactory.ts} (88%) rename packages/backend-plugin-api/src/services/definitions/{HealthService.ts => RootHealthService.ts} (83%) diff --git a/docs/backend-system/core-services/01-index.md b/docs/backend-system/core-services/01-index.md index 63324292c1..3be12b2e26 100644 --- a/docs/backend-system/core-services/01-index.md +++ b/docs/backend-system/core-services/01-index.md @@ -20,7 +20,6 @@ import { coreServices } from '@backstage/backend-plugin-api'; - [Cache Service](./cache.md) - Key-value store for caching data. - [Database Service](./database.md) - Database access and management via [knex](https://knexjs.org/). - [Discovery Service](./discovery.md) - Service discovery for inter-plugin communication. -- [Health Service](./health.md) - Health check endpoints for the backend. - [Http Auth Service](./http-auth.md) - Authentication of HTTP requests. - [Http Router Service](./http-router.md) - HTTP route registration for plugins. - [Identity Service](./identity.md) - Deprecated user authentication service, use the [Auth Service](./auth.md) instead. @@ -29,6 +28,7 @@ import { coreServices } from '@backstage/backend-plugin-api'; - [Permissions Service](./permissions.md) - Permission system integration for authorization of user actions. - [Plugin Metadata Service](./plugin-metadata.md) - Built-in service for accessing metadata about the current plugin. - [Root Config Service](./root-config.md) - Access to static configuration. +- [Root Health Service](./root-health.md) - Health check endpoints for the backend. - [Root Http Router Service](./root-http-router.md) - HTTP route registration for root services. - [Root Lifecycle Service](./root-lifecycle.md) - Registration of backend startup and shutdown lifecycle hooks. - [Root Logger Service](./root-logger.md) - Root-level logging. diff --git a/docs/backend-system/core-services/health.md b/docs/backend-system/core-services/root-health.md similarity index 100% rename from docs/backend-system/core-services/health.md rename to docs/backend-system/core-services/root-health.md diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index c29d973997..2d84bae308 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -24,13 +24,13 @@ "./cache": "./src/entrypoints/cache/index.ts", "./database": "./src/entrypoints/database/index.ts", "./discovery": "./src/entrypoints/discovery/index.ts", - "./health": "./src/entrypoints/health/index.ts", "./httpAuth": "./src/entrypoints/httpAuth/index.ts", "./httpRouter": "./src/entrypoints/httpRouter/index.ts", "./lifecycle": "./src/entrypoints/lifecycle/index.ts", "./logger": "./src/entrypoints/logger/index.ts", "./permissions": "./src/entrypoints/permissions/index.ts", "./rootConfig": "./src/entrypoints/rootConfig/index.ts", + "./rootHealth": "./src/entrypoints/rootHealth/index.ts", "./rootHttpRouter": "./src/entrypoints/rootHttpRouter/index.ts", "./rootLifecycle": "./src/entrypoints/rootLifecycle/index.ts", "./rootLogger": "./src/entrypoints/rootLogger/index.ts", @@ -55,9 +55,6 @@ "discovery": [ "src/entrypoints/discovery/index.ts" ], - "health": [ - "src/entrypoints/health/index.ts" - ], "httpAuth": [ "src/entrypoints/httpAuth/index.ts" ], @@ -76,6 +73,9 @@ "rootConfig": [ "src/entrypoints/rootConfig/index.ts" ], + "rootHealth": [ + "src/entrypoints/rootHealth/index.ts" + ], "rootHttpRouter": [ "src/entrypoints/rootHttpRouter/index.ts" ], diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 453c5fe592..e3195748a6 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -24,13 +24,13 @@ import { authServiceFactory } from '@backstage/backend-defaults/auth'; import { cacheServiceFactory } from '@backstage/backend-defaults/cache'; import { databaseServiceFactory } from '@backstage/backend-defaults/database'; import { discoveryServiceFactory } from '@backstage/backend-defaults/discovery'; -import { rootHealthServiceFactory } from './entrypoints/rootHealth'; import { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; import { rootConfigServiceFactory } from '@backstage/backend-defaults/rootConfig'; +import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { rootLoggerServiceFactory } from '@backstage/backend-defaults/rootLogger'; @@ -51,6 +51,7 @@ export const defaultServiceFactories = [ lifecycleServiceFactory(), loggerServiceFactory(), permissionsServiceFactory(), + rootHealthServiceFactory(), rootHttpRouterServiceFactory(), rootLifecycleServiceFactory(), rootLoggerServiceFactory(), @@ -59,7 +60,6 @@ export const defaultServiceFactories = [ userInfoServiceFactory(), urlReaderServiceFactory(), eventsServiceFactory(), - rootHealthServiceFactory(), ]; /** diff --git a/packages/backend-defaults/src/entrypoints/health/index.ts b/packages/backend-defaults/src/entrypoints/rootHealth/index.ts similarity index 89% rename from packages/backend-defaults/src/entrypoints/health/index.ts rename to packages/backend-defaults/src/entrypoints/rootHealth/index.ts index 4aeb4b7979..35225b39c4 100644 --- a/packages/backend-defaults/src/entrypoints/health/index.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { healthServiceFactory } from './healthServiceFactory'; +export { rootHealthServiceFactory } from './rootHealthServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts similarity index 88% rename from packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts rename to packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts index 7e160cbd82..fd786e2b28 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts @@ -1,5 +1,5 @@ import { mockServices } from '@backstage/backend-test-utils'; -import { DefaultHealthService } from './healthServiceFactory'; +import { DefaultRootHealthService } from './rootHealthServiceFactory'; /* * Copyright 2024 The Backstage Authors @@ -16,10 +16,10 @@ import { DefaultHealthService } from './healthServiceFactory'; * See the License for the specific language governing permissions and * limitations under the License. */ -describe('DefaultHealthService', () => { +describe('DefaultRootHealthService', () => { describe('readiness', () => { it(`should return a 500 response if the server hasn't started yet`, async () => { - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); await expect(service.getReadiness()).resolves.toEqual({ @@ -38,7 +38,7 @@ describe('DefaultHealthService', () => { fn => (mockServerStartedFn = fn), ); - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle, }); @@ -61,7 +61,7 @@ describe('DefaultHealthService', () => { fn => (mockServerStoppedFn = fn), ); - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); @@ -79,7 +79,7 @@ describe('DefaultHealthService', () => { describe('liveness', () => { it('should return 200 if the server has started', async () => { - const service = new DefaultHealthService({ + const service = new DefaultRootHealthService({ lifecycle: mockServices.rootLifecycle.mock(), }); diff --git a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts similarity index 88% rename from packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts rename to packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts index 652ad8758f..3a00db8285 100644 --- a/packages/backend-defaults/src/entrypoints/health/healthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts @@ -15,14 +15,14 @@ */ import { - HealthService, + RootHealthService, RootLifecycleService, coreServices, createServiceFactory, } from '@backstage/backend-plugin-api'; /** @internal */ -export class DefaultHealthService implements HealthService { +export class DefaultRootHealthService implements RootHealthService { #isRunning = false; constructor(readonly options: { lifecycle: RootLifecycleService }) { @@ -53,12 +53,12 @@ export class DefaultHealthService implements HealthService { /** * @public */ -export const healthServiceFactory = createServiceFactory({ +export const rootHealthServiceFactory = createServiceFactory({ service: coreServices.health, deps: { lifecycle: coreServices.rootLifecycle, }, async factory({ lifecycle }) { - return new DefaultHealthService({ lifecycle }); + return new DefaultRootHealthService({ lifecycle }); }, }); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts index 012a268e02..13691ede28 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -1,4 +1,4 @@ -import { HealthService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; /* * Copyright 2024 The Backstage Authors @@ -19,7 +19,7 @@ import { HealthService } from '@backstage/backend-plugin-api'; import Router from 'express-promise-router'; import { Request, Response } from 'express'; -export function createHealthRouter(options: { health: HealthService }) { +export function createHealthRouter(options: { health: RootHealthService }) { const router = Router(); router.get( diff --git a/packages/backend-plugin-api/src/services/definitions/HealthService.ts b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts similarity index 83% rename from packages/backend-plugin-api/src/services/definitions/HealthService.ts rename to packages/backend-plugin-api/src/services/definitions/RootHealthService.ts index b2dc4f415e..ac482b5dbb 100644 --- a/packages/backend-plugin-api/src/services/definitions/HealthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts @@ -17,7 +17,13 @@ /** * @public */ -export interface HealthService { +export interface RootHealthService { + /** + * Get the liveness status of the backend. + */ getLiveness(): Promise<{ status: number; payload?: any }>; + /** + * Get the readiness status of the backend. + */ getReadiness(): Promise<{ status: number; payload?: any }>; } diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index af0d991f58..5e30d444fd 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -32,7 +32,7 @@ export type { export type { RootConfigService } from './RootConfigService'; export type { DatabaseService } from './DatabaseService'; export type { DiscoveryService } from './DiscoveryService'; -export type { HealthService } from './HealthService'; +export type { RootHealthService } from './RootHealthService'; export type { HttpRouterService, HttpRouterServiceAuthPolicy, diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index a59d053b95..5055a9eae8 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -20,11 +20,11 @@ import { HostDiscovery, discoveryServiceFactory, } from '@backstage/backend-defaults/discovery'; -import { healthServiceFactory } from '@backstage/backend-defaults/health'; import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter'; import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; import { loggerServiceFactory } from '@backstage/backend-defaults/logger'; import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; +import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth'; import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; @@ -345,8 +345,8 @@ export namespace mockServices { })); } - export namespace health { - export const factory = healthServiceFactory; + export namespace rootHealth { + export const factory = rootHealthServiceFactory; export const mock = simpleMock(coreServices.health, () => ({ getLiveness: jest.fn(), getReadiness: jest.fn(), From 5c4e876e62afbfa56ff3105a2eca0811a7942e8f Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 13 Jun 2024 14:25:02 +0200 Subject: [PATCH 162/860] health api reports Signed-off-by: Vincenzo Scamporlino --- ...ort-health.md => api-report-rootHealth.md} | 7 +++-- packages/backend-plugin-api/api-report.md | 28 +++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) rename packages/backend-defaults/{api-report-health.md => api-report-rootHealth.md} (65%) diff --git a/packages/backend-defaults/api-report-health.md b/packages/backend-defaults/api-report-rootHealth.md similarity index 65% rename from packages/backend-defaults/api-report-health.md rename to packages/backend-defaults/api-report-rootHealth.md index 795bdaac78..ffa067605a 100644 --- a/packages/backend-defaults/api-report-health.md +++ b/packages/backend-defaults/api-report-rootHealth.md @@ -3,11 +3,14 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { HealthService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; // @public (undocumented) -export const healthServiceFactory: () => ServiceFactory; +export const rootHealthServiceFactory: () => ServiceFactory< + RootHealthService, + 'root' +>; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index ee5aecd63b..f527e366c0 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -194,7 +194,7 @@ export namespace coreServices { const rootConfig: ServiceRef; const database: ServiceRef; const discovery: ServiceRef; - const health: ServiceRef; + const health: ServiceRef; const httpAuth: ServiceRef; const httpRouter: ServiceRef; const lifecycle: ServiceRef; @@ -334,20 +334,6 @@ export type ExtensionPoint = { // @public @deprecated (undocumented) export type ExtensionPointConfig = CreateExtensionPointOptions; -// @public (undocumented) -export interface HealthService { - // (undocumented) - getLiveness(): Promise<{ - status: number; - payload?: any; - }>; - // (undocumented) - getReadiness(): Promise<{ - status: number; - payload?: any; - }>; -} - // @public export interface HttpAuthService { credentials( @@ -515,6 +501,18 @@ export function resolveSafeChildPath(base: string, path: string): string; // @public export interface RootConfigService extends Config {} +// @public (undocumented) +export interface RootHealthService { + getLiveness(): Promise<{ + status: number; + payload?: any; + }>; + getReadiness(): Promise<{ + status: number; + payload?: any; + }>; +} + // @public export interface RootHttpRouterService { use(path: string, handler: Handler): void; From 73a45650e2872fdad10ea9edc9f37baa1e847957 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 12:11:08 +0200 Subject: [PATCH 163/860] api reports Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/api-report.md | 4 ---- .../api-report-rootHttpRouter.md | 2 ++ .../rootHealth/rootHealthServiceFactory.ts | 2 +- .../rootHttpRouterServiceFactory.ts | 2 +- packages/backend-plugin-api/api-report.md | 2 +- .../src/services/definitions/coreServices.ts | 4 ++-- packages/backend-test-utils/api-report.md | 20 +++++++++---------- .../src/next/services/mockServices.ts | 2 +- 8 files changed, 18 insertions(+), 20 deletions(-) diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index a18f027273..7518f8e2cc 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -18,7 +18,6 @@ import { ErrorRequestHandler } from 'express'; import { Express as Express_2 } from 'express'; import { Format } from 'logform'; import { Handler } from 'express'; -import { HealthService } from '@backstage/backend-plugin-api'; import { HelmetOptions } from 'helmet'; import * as http from 'http'; import { HttpAuthService } from '@backstage/backend-plugin-api'; @@ -127,9 +126,6 @@ export const discoveryServiceFactory: () => ServiceFactory< // @public @deprecated (undocumented) export type ExtendedHttpServer = ExtendedHttpServer_2; -// @public (undocumented) -export const healthServiceFactory: () => ServiceFactory; - // @public @deprecated export class HostDiscovery implements DiscoveryService { static fromConfig( diff --git a/packages/backend-defaults/api-report-rootHttpRouter.md b/packages/backend-defaults/api-report-rootHttpRouter.md index b753406202..d9727fd36d 100644 --- a/packages/backend-defaults/api-report-rootHttpRouter.md +++ b/packages/backend-defaults/api-report-rootHttpRouter.md @@ -121,6 +121,8 @@ export interface RootHttpRouterConfigureContext { // (undocumented) config: RootConfigService; // (undocumented) + healthRouter: RequestHandler; + // (undocumented) lifecycle: LifecycleService; // (undocumented) logger: LoggerService; diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts index 3a00db8285..c8b4ad5394 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts @@ -54,7 +54,7 @@ export class DefaultRootHealthService implements RootHealthService { * @public */ export const rootHealthServiceFactory = createServiceFactory({ - service: coreServices.health, + service: coreServices.rootHealth, deps: { lifecycle: coreServices.rootLifecycle, }, diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index 5f22cf5ced..22f5c2f310 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -77,7 +77,7 @@ export const rootHttpRouterServiceFactory = createServiceFactory( config: coreServices.rootConfig, rootLogger: coreServices.rootLogger, lifecycle: coreServices.rootLifecycle, - health: coreServices.health, + health: coreServices.rootHealth, }, async factory({ config, rootLogger, lifecycle, health }) { const { indexPath, configure = defaultConfigure } = options ?? {}; diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index f527e366c0..ef5aa22cf4 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -194,7 +194,7 @@ export namespace coreServices { const rootConfig: ServiceRef; const database: ServiceRef; const discovery: ServiceRef; - const health: ServiceRef; + const rootHealth: ServiceRef; const httpAuth: ServiceRef; const httpRouter: ServiceRef; const lifecycle: ServiceRef; diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts index 36ec0151c5..33d1da2903 100644 --- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts +++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts @@ -105,9 +105,9 @@ export namespace coreServices { /** * The service reference for the plugin scoped {@link RootHealthService}. */ - export const health = createServiceRef< + export const rootHealth = createServiceRef< import('./RootHealthService').RootHealthService - >({ id: 'core.health', scope: 'root' }); + >({ id: 'core.rootHealth', scope: 'root' }); /** * Authentication of HTTP requests. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 07b393b653..a2fb4b7674 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -21,7 +21,6 @@ import { DiscoveryService } from '@backstage/backend-plugin-api'; import { EventsService } from '@backstage/plugin-events-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; -import { HealthService } 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'; @@ -33,6 +32,7 @@ import { LifecycleService } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; import { PermissionsService } from '@backstage/backend-plugin-api'; import { RootConfigService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; import { RootHttpRouterFactoryOptions } from '@backstage/backend-defaults/rootHttpRouter'; import { RootHttpRouterService } from '@backstage/backend-plugin-api'; import { RootLifecycleService } from '@backstage/backend-plugin-api'; @@ -200,15 +200,6 @@ export namespace mockServices { partialImpl?: Partial | undefined, ) => ServiceMock; } - // (undocumented) - export namespace health { - const // (undocumented) - factory: () => ServiceFactory; - const // (undocumented) - mock: ( - partialImpl?: Partial | undefined, - ) => ServiceMock; - } export function httpAuth(options?: { pluginId?: string; defaultCredentials?: BackstageCredentials; @@ -290,6 +281,15 @@ export namespace mockServices { ) => ServiceFactory; } // (undocumented) + export namespace rootHealth { + const // (undocumented) + factory: () => ServiceFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; + } + // (undocumented) export namespace rootHttpRouter { const // (undocumented) factory: ( diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 5055a9eae8..d56179d958 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -347,7 +347,7 @@ export namespace mockServices { export namespace rootHealth { export const factory = rootHealthServiceFactory; - export const mock = simpleMock(coreServices.health, () => ({ + export const mock = simpleMock(coreServices.rootHealth, () => ({ getLiveness: jest.fn(), getReadiness: jest.fn(), })); From e36e507d592c3a6011b6834cd8a0b751bc38c339 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 12:20:18 +0200 Subject: [PATCH 164/860] docs: update root health docs Signed-off-by: Vincenzo Scamporlino --- .../core-services/root-health.md | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index 9a69891624..2a6625fd70 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -1,38 +1,40 @@ --- -id: health -title: Heath Service +id: root-health +title: Root Health Service sidebar_label: Health description: Documentation for the Health service --- -The Health service provides some health check endpoints for the plugins. By default, it attaches `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints to the backend server, which return a JSON object with the status of the backend services. +The Root Health service provides some health check endpoints for the backend. By default, the `rootHttpRouter` exposes a `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints, which return a JSON object with the status of the backend services according the implementation of the Root Health Service. ## Configuring the service -The following example is how you can override the health service to add custom endpoints. +The following example is how you can override the health service implementation. ```ts -import { coreServices } from '@backstage/backend-plugin-api'; +import { RootHealthService, coreServices } from '@backstage/backend-plugin-api'; import { WinstonLogger } from '@backstage/backend-app-api'; const backend = createBackend(); +class MyRootHealthService implements RootHealthService { + async getLiveness(): Promise<{ status: number; payload?: any }> { + // provide your own implementation + return { status: 200, payload: { status: 'ok' } }; + } + + async getReadiness(): Promise<{ status: number; payload?: any }> { + // provide your own implementation + return { status: 200, payload: { status: 'ok' } }; + } +} + backend.add( createServiceFactory({ - service: coreServices.health, - deps: { - rootHttpRouter: coreServices.rootHttpRouter, - }, - async factory({ rootHttpRouter }) { - rootHttpRouter.get('.backstage/health/v1/readiness', async (req, res) => { - res.json({ status: 'ok' }); - }); - - rootHttpRouter.get('.backstage/health/v1/liveness', async (req, res) => { - res.json({ status: 'ok' }); - }); - - return {}; + service: coreServices.rootHealth, + deps: {}, + async factory({}) { + return new MyRootHealthService(); }, }), ); From 4e8455f0bd18bf4e779df3b2484f9ac1dfd2430f Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 12:43:34 +0200 Subject: [PATCH 165/860] Apply suggestions from code review Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 2 +- .changeset/serious-kings-trade.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md index acd9764fe6..14798b6b39 100644 --- a/.changeset/bright-panthers-leave.md +++ b/.changeset/bright-panthers-leave.md @@ -4,4 +4,4 @@ '@backstage/backend-app-api': patch --- -Added a new health service which adds new endpoints for health checks. +Added a new Root Health Service which adds new endpoints for health checks. diff --git a/.changeset/serious-kings-trade.md b/.changeset/serious-kings-trade.md index c07e92b88a..826392bf98 100644 --- a/.changeset/serious-kings-trade.md +++ b/.changeset/serious-kings-trade.md @@ -2,4 +2,4 @@ '@backstage/backend-test-utils': patch --- -Added mock for health service in `mockServices`. +Added mock for the Root Health Service in `mockServices`. From 9a86dc124f64668ff0a2c7f9dcdbe50a1604f1c4 Mon Sep 17 00:00:00 2001 From: Caio Augusto Date: Thu, 20 Jun 2024 10:07:56 -0300 Subject: [PATCH 166/860] 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 73b4e727e9a3c31460f1b8ba4533562404a9b2ad Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:22:35 +0200 Subject: [PATCH 167/860] Update .changeset/bright-panthers-leave.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Vincenzo Scamporlino --- .changeset/bright-panthers-leave.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md index 14798b6b39..35d9c0f869 100644 --- a/.changeset/bright-panthers-leave.md +++ b/.changeset/bright-panthers-leave.md @@ -1,7 +1,6 @@ --- '@backstage/backend-plugin-api': patch '@backstage/backend-defaults': patch -'@backstage/backend-app-api': patch --- Added a new Root Health Service which adds new endpoints for health checks. From cd22b4066660158b247ba2c9d728f6a777e44351 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:31:34 +0200 Subject: [PATCH 168/860] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/root-health.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index 2a6625fd70..cdf18aa1f9 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -9,11 +9,10 @@ The Root Health service provides some health check endpoints for the backend. By ## Configuring the service -The following example is how you can override the health service implementation. +The following example shows how you can override the root health service implementation. ```ts import { RootHealthService, coreServices } from '@backstage/backend-plugin-api'; -import { WinstonLogger } from '@backstage/backend-app-api'; const backend = createBackend(); From 7df5c8875c12058e6b3e61827f074c324e3d82c0 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:41:19 +0200 Subject: [PATCH 169/860] backend-defaults: test tweaks Signed-off-by: Vincenzo Scamporlino --- .../rootHealthServiceFactory.test.ts | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts index fd786e2b28..0eee5c18c6 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts @@ -1,6 +1,3 @@ -import { mockServices } from '@backstage/backend-test-utils'; -import { DefaultRootHealthService } from './rootHealthServiceFactory'; - /* * Copyright 2024 The Backstage Authors * @@ -16,6 +13,10 @@ import { DefaultRootHealthService } from './rootHealthServiceFactory'; * See the License for the specific language governing permissions and * limitations under the License. */ + +import { mockServices } from '@backstage/backend-test-utils'; +import { DefaultRootHealthService } from './rootHealthServiceFactory'; + describe('DefaultRootHealthService', () => { describe('readiness', () => { it(`should return a 500 response if the server hasn't started yet`, async () => { @@ -32,11 +33,11 @@ describe('DefaultRootHealthService', () => { }); it('should return 200 if the server has started', async () => { - const lifecycle = mockServices.rootLifecycle.mock(); let mockServerStartedFn = () => {}; - lifecycle.addStartupHook.mockImplementation( - fn => (mockServerStartedFn = fn), - ); + + const lifecycle = mockServices.rootLifecycle.mock({ + addStartupHook: jest.fn(fn => (mockServerStartedFn = fn)), + }); const service = new DefaultRootHealthService({ lifecycle, @@ -51,18 +52,16 @@ describe('DefaultRootHealthService', () => { }); it(`should return a 500 response if the server has stopped`, async () => { - const lifecycle = mockServices.rootLifecycle.mock(); let mockServerStartedFn = () => {}; let mockServerStoppedFn = () => {}; - lifecycle.addStartupHook.mockImplementation( - fn => (mockServerStartedFn = fn), - ); - lifecycle.addShutdownHook.mockImplementation( - fn => (mockServerStoppedFn = fn), - ); + + const lifecycle = mockServices.rootLifecycle.mock({ + addStartupHook: jest.fn(fn => (mockServerStartedFn = fn)), + addShutdownHook: jest.fn(fn => (mockServerStoppedFn = fn)), + }); const service = new DefaultRootHealthService({ - lifecycle: mockServices.rootLifecycle.mock(), + lifecycle, }); mockServerStartedFn(); From 878f2efc514810e03567d167b61b92f66cd74790 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Jun 2024 15:45:02 +0200 Subject: [PATCH 170/860] backend-plugin-api: fix typings in health service Signed-off-by: Vincenzo Scamporlino --- docs/backend-system/core-services/root-health.md | 4 ++-- packages/backend-plugin-api/api-report.md | 4 ++-- .../src/services/definitions/RootHealthService.ts | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index cdf18aa1f9..fc73ba9546 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -17,12 +17,12 @@ import { RootHealthService, coreServices } from '@backstage/backend-plugin-api'; const backend = createBackend(); class MyRootHealthService implements RootHealthService { - async getLiveness(): Promise<{ status: number; payload?: any }> { + async getLiveness() { // provide your own implementation return { status: 200, payload: { status: 'ok' } }; } - async getReadiness(): Promise<{ status: number; payload?: any }> { + async getReadiness() { // provide your own implementation return { status: 200, payload: { status: 'ok' } }; } diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index ef5aa22cf4..e9762f652e 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -505,11 +505,11 @@ export interface RootConfigService extends Config {} export interface RootHealthService { getLiveness(): Promise<{ status: number; - payload?: any; + payload?: JsonValue; }>; getReadiness(): Promise<{ status: number; - payload?: any; + payload?: JsonValue; }>; } diff --git a/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts index ac482b5dbb..e6c56e8654 100644 --- a/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/RootHealthService.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { JsonValue } from '@backstage/types'; + /** * @public */ @@ -21,9 +23,9 @@ export interface RootHealthService { /** * Get the liveness status of the backend. */ - getLiveness(): Promise<{ status: number; payload?: any }>; + getLiveness(): Promise<{ status: number; payload?: JsonValue }>; /** * Get the readiness status of the backend. */ - getReadiness(): Promise<{ status: number; payload?: any }>; + getReadiness(): Promise<{ status: number; payload?: JsonValue }>; } From 2537c3f345ecc5b5755036695d1357c42ddad74e Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Thu, 20 Jun 2024 16:32:26 +0200 Subject: [PATCH 171/860] Extend tests for subgroups Signed-off-by: Hghtwr --- .yarnrc.yml | 8 +- .../src/__testUtils__/handlers.ts | 63 ++++- .../src/__testUtils__/mocks.ts | 224 +++++++++++++++++- .../GitlabOrgDiscoveryEntityProvider.test.ts | 223 ++++++++++++++++- .../GitlabOrgDiscoveryEntityProvider.ts | 16 +- 5 files changed, 518 insertions(+), 16 deletions(-) diff --git a/.yarnrc.yml b/.yarnrc.yml index 466074db0a..18069eb1a7 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,13 +1,17 @@ enableGlobalCache: true +httpProxy: "http://sia-lb.telekom.de:8080" + httpTimeout: 300000 +httpsProxy: "http://sia-lb.telekom.de:8080" + nodeLinker: node-modules -npmRegistryServer: 'https://registry.npmjs.org/' +npmRegistryServer: "https://registry.npmjs.org/" plugins: - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs - spec: '@yarnpkg/plugin-workspace-tools' + spec: "@yarnpkg/plugin-workspace-tools" yarnPath: .yarn/releases/yarn-3.8.1.cjs diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index 80aa0370d3..04a95c4332 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -19,6 +19,7 @@ import { all_groups_response, all_projects_response, all_saas_users_response, + subgroup_saas_users_response, all_users_response, apiBaseUrl, apiBaseUrlSaas, @@ -68,6 +69,13 @@ const httpHandlers = [ return res(ctx.json(all_saas_users_response)); }), + rest.get( + `${apiBaseUrlSaas}/groups/subgroup1/members/all`, + (_req, res, ctx) => { + return res(ctx.json(subgroup_saas_users_response)); // To-DO change + }, + ), + /** * Users REST endpoint mocks */ @@ -186,7 +194,34 @@ const graphqlHandlers = [ .link(graphQlBaseUrl) .query('getGroupMembers', async (req, res, ctx) => { const { group, relations } = req.variables; - + // group is actually full_path + if (group === 'group1/subgroup1' && relations.includes('DIRECT')) { + return res( + ctx.data({ + group: { + groupMembers: { + nodes: [ + { + user: { + id: 'gid://gitlab/User/1', + username: 'user1', + publicEmail: 'user1@example.com', + name: 'user1', + state: 'active', + webUrl: 'user1.com', + avatarUrl: 'user1', + }, + }, + ], + pageInfo: { + endCursor: 'end', + hasNextPage: false, + }, + }, + }, + }), + ); + } if (group === 'group1' && relations.includes('DIRECT')) { return res( ctx.data({ @@ -367,7 +402,31 @@ const graphqlHandlers = [ ]), ); } - + if (group === 'group1') { + return res( + ctx.data({ + group: { + descendantGroups: { + nodes: [ + { + id: 'gid://gitlab/Group/6', + name: 'subgroup1', + description: 'description1', + fullPath: 'group1/subgroup1', + parent: { + id: '123', + }, + }, + ], + pageInfo: { + endCursor: 'end', + hasNextPage: false, + }, + }, + }, + }), + ); + } if (group === 'group-with-parent') { return res( ctx.data({ diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts index e3154eb1ce..b30f80888f 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts @@ -822,6 +822,12 @@ export const all_groups_response: GitLabGroup[] = [ description: '', full_path: 'parent1/nonMatchingGroup', }, + { + id: 6, + name: 'subgroup1', + description: '', + full_path: 'group1/subgroup1', + }, ]; export const group_with_parent: MockObject[] = [ @@ -1708,7 +1714,7 @@ export const expected_full_org_scan_entities: MockObject[] = [ name: 'JohnDoe', }, spec: { - memberOf: ['group1'], + memberOf: ['group1', 'group1-subgroup1'], profile: { displayName: 'John Doe', email: 'john.doe@company.com', @@ -1815,6 +1821,30 @@ export const expected_full_org_scan_entities: MockObject[] = [ }, locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://example.com/group1/subgroup1', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/group1/subgroup1', + 'example.com/team-path': 'group1/subgroup1', + }, + name: 'group1-subgroup1', + }, + spec: { + children: [], + profile: { + displayName: 'subgroup1', + }, + type: 'team', + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, ]; export const expected_full_org_scan_entities_saas: MockObject[] = [ @@ -1871,3 +1901,195 @@ export const expected_full_org_scan_entities_saas: MockObject[] = [ locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, ]; + +export const subgroup_saas_users_response: MockObject[] = [ + { + access_level: 30, + created_at: '2023-07-17T08:58:34.984Z', + expires_at: null, + id: 12, + username: 'testuser1', + name: 'Test User 1', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.com/testuser1', + email: 'testuser1@example.com', + group_saml_identity: { + provider: 'group_saml', + extern_uid: '51', + saml_provider_id: 1, + }, + is_using_seat: true, + membership_state: 'active', + }, + { + access_level: 50, + created_at: '2023-07-15T08:58:34.984Z', + expires_at: '2023-10-26', + id: 54, + username: 'group_100_bot_23dc8057bef66e05181f39be4652577c', + name: 'Token Bot', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: + 'https://gitlab.com/group_100_bot_23dc8057bef66e05181f39be4652577c', + group_saml_identity: null, + is_using_seat: false, + membership_state: 'active', + }, +]; + +export const expected_subgroup_org_scan_entities_saas: MockObject[] = [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://gitlab.com/testuser1', + 'backstage.io/managed-by-origin-location': + 'url:https://gitlab.com/testuser1', + 'gitlab.com/user-login': 'https://gitlab.com/testuser1', + 'gitlab.com/saml-external-uid': '51', + }, + name: 'testuser1', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Test User 1', + email: 'testuser1@example.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, +]; + +// Simulate return of all users but only with membership of the descendants of config.group +export const expected_group_org_scan_entities: MockObject[] = [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://example.com/JohnDoe', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/JohnDoe', + 'example.com/user-login': 'https://gitlab.example/john_doe', + }, + name: 'JohnDoe', + }, + spec: { + memberOf: ['subgroup1'], + profile: { + displayName: 'John Doe', + email: 'john.doe@company.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://example.com/JaneDoe', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/JaneDoe', + 'example.com/user-login': 'https://gitlab.example/jane_doe', + }, + name: 'JaneDoe', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Jane Doe', + email: 'jane.doe@company.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://example.com/MarySmith', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/MarySmith', + 'example.com/user-login': 'https://gitlab.example/mary_smith', + }, + name: 'MarySmith', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Mary Smith', + email: 'mary.smith@company.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://example.com/MarioMario', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/MarioMario', + 'example.com/user-login': 'https://gitlab.example/mario_mario', + }, + name: 'MarioMario', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Mario Mario', + email: 'mario.mario-company.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://example.com/group1/subgroup1', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/group1/subgroup1', + 'example.com/team-path': 'group1/subgroup1', + }, + name: 'subgroup1', + }, + spec: { + children: [], + profile: { + displayName: 'subgroup1', + }, + type: 'team', + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, +]; 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 5a60f1b4b3..8cf046909d 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -175,6 +175,220 @@ describe('GitlabOrgDiscoveryEntityProvider - configuration', () => { }); }); +// This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas +it('SaaS: should get all saas root group users when restrictUsersToGroup is not set', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_org_scan_entities_saas, // + }); +}); + +// This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas +it('SaaS: should get all saas root group users when restrictUsersToGroup is false', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + restrictUsersToGroup: false, + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_org_scan_entities_saas, // + }); +}); + +// This should return only members of the SaaS subgroup (group1/subgroup1) -> expected_subgroup_org_scan_entities_saas +it('SaaS: should get only subgroup users when restrictUsersToGroup is true', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1/subgroup1', + restrictUsersToGroup: true, + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_subgroup_org_scan_entities_saas, + }); +}); + +// This should return all members of the self-hosted instance regardless of the group set -> expected_full_org_scan_entities +it('Self-hosted: should get all instance users when restrictUsersToGroup is not set', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'example.com', + apiBaseUrl: 'https://example.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'example.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_group_org_scan_entities, // This should deliver all users but only their membership in subgroups of config.group + }); +}); + describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { it('should apply full update on scheduled execution', async () => { const config = new ConfigReader(mock.config_org_integration); @@ -260,15 +474,16 @@ describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { const taskDef = schedule.getTasks()[0]; await (taskDef.fn as () => Promise)(); - const userEntities = mock.expected_full_org_scan_entities.filter( + const entities = mock.expected_full_org_scan_entities.filter( element => element.entity.metadata.name !== 'MarioMario', ); // filter out user with non matched e-mail - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(userEntities).not.toHaveLength(mock.all_users_response.length); + expect(entities).not.toHaveLength( + mock.expected_full_org_scan_entities.length, + ); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ type: 'full', - entities: userEntities, + entities: entities, }); }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index ce545ebe84..e2043e0393 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -107,7 +107,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { private userTransformer: UserTransformer; private groupEntitiesTransformer: GroupEntitiesTransformer; private groupNameTransformer: GroupNameTransformer; - private readonly gitLabClient: GitLabClient; + public readonly gitLabClient: GitLabClient; static fromConfig( config: Config, @@ -356,13 +356,14 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { let groups; let users; - // Doesn't matter if we are on SaaS or not, we can either get the users from the defined group or from the root group. + // Self-hosted: Fetch the users either from the defined group (restrictUsersToGroup) or fetch all users from the GitLab instance + // SaaS: Fetch the users from the defined group (restrictUsersToGroup) or fetch all users from the root group. if (this.gitLabClient.isSelfManaged() && this.config.restrictUsersToGroup) { groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) .items; users = paginated( options => - this.gitLabClient.listGroupMembers(this.config.group, options), + this.gitLabClient.listGroupMembers(this.config.group, options), // calls /groups//members { page: 1, per_page: 100, @@ -381,17 +382,18 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }, ); users = paginated( - options => this.gitLabClient.listUsers(options), + options => this.gitLabClient.listUsers(options), // calls /users? { page: 1, per_page: 100, active: true }, ); } - // For SaaS, the only difference is the root group + // SaaS: Fetch the users from the defined group (restrictUsersToGroup) or fetch all users from the root group. else { groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) .items; + const rootGroupSplit = this.config.group.split('/'); const rootGroup = this.config.restrictUsersToGroup - ? this.config.group - : this.config.group.split('/')[0]; + ? rootGroupSplit[rootGroupSplit.length - 1] + : rootGroupSplit[0]; users = paginated( options => this.gitLabClient.listSaaSUsers(rootGroup, options), { From 18daa1faaa7bc0e3cbf2a7c40403649a68083d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Gothuey?= Date: Thu, 20 Jun 2024 16:28:15 +0200 Subject: [PATCH 172/860] Fix extra closing parenthesis in code sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël Gothuey Signed-off-by: gaelgoth --- .../backend-system/building-plugins-and-modules/02-testing.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 8a2dd0414d..0739ad24aa 100644 --- a/docs/backend-system/building-plugins-and-modules/02-testing.md +++ b/docs/backend-system/building-plugins-and-modules/02-testing.md @@ -138,8 +138,10 @@ describe('MyDatabaseClass', () => { await knex('foo').insert({ value: 2 }); // drive your system under test as usual await expect(subject.foos()).resolves.toEqual([{ value: 2 }]); - }); + }, + ); }); +}); ``` If you want to pass the test database instance into backend plugins or services, From fc6db7af1d84959b34b47655cda3c27b0a9baa63 Mon Sep 17 00:00:00 2001 From: Christopher Diaz Date: Thu, 20 Jun 2024 17:10:40 -0400 Subject: [PATCH 173/860] update tests and API reports Signed-off-by: Christopher Diaz --- .../api-report.md | 1 + .../githubEnvironment.examples.test.ts | 2 + .../src/actions/githubEnvironment.test.ts | 48 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/plugins/scaffolder-backend-module-github/api-report.md b/plugins/scaffolder-backend-module-github/api-report.md index beabdfaaf6..94b642bdbf 100644 --- a/plugins/scaffolder-backend-module-github/api-report.md +++ b/plugins/scaffolder-backend-module-github/api-report.md @@ -77,6 +77,7 @@ export function createGithubEnvironmentAction(options: { } | undefined; customBranchPolicyNames?: string[] | undefined; + customTagPolicyNames?: string[] | undefined; environmentVariables?: | { [key: string]: string; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts index ecb4e9f092..9d4395eb7a 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts @@ -171,6 +171,7 @@ describe('github:environment:create examples', () => { repo: 'repository', environment_name: 'envname', name: 'main', + type: 'branch', }); expect( @@ -180,6 +181,7 @@ describe('github:environment:create examples', () => { repo: 'repository', environment_name: 'envname', name: '*.*.*', + type: 'branch', }); expect( 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 16872525b4..a8d8c4ef2e 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts @@ -121,6 +121,7 @@ describe('github:environment:create', () => { }, }); }); + it('should work specify deploymentBranchPolicy custom', async () => { await action.handler({ ...mockContext, @@ -153,6 +154,7 @@ describe('github:environment:create', () => { repo: 'repository', environment_name: 'envname', name: 'main', + type: 'branch', }); expect( mockOctokit.rest.repos.createDeploymentBranchPolicy, @@ -161,6 +163,52 @@ describe('github:environment:create', () => { repo: 'repository', environment_name: 'envname', name: '*.*.*', + type: 'branch', + }); + }); + + it('should work specify deploymentTagPolicy custom', async () => { + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + deploymentBranchPolicy: { + protected_branches: false, + custom_branch_policies: true, + }, + customTagPolicyNames: ['main', '*.*.*'], + }, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: { + protected_branches: false, + custom_branch_policies: true, + }, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + name: 'main', + type: 'tag', + }); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + name: '*.*.*', + type: 'tag', }); }); From 8839381d6a0980df52604bc6fd8cca5a44931afc Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Fri, 21 Jun 2024 00:41:13 -0400 Subject: [PATCH 174/860] 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 c67d887ad17f3def89c48d9a5dedb6d89b81bb5b Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Fri, 21 Jun 2024 09:52:36 +0200 Subject: [PATCH 175/860] add self-hosted test suite, fix format Signed-off-by: Hghtwr --- .yarnrc.yml | 8 +- .../src/__testUtils__/handlers.ts | 4 + .../src/__testUtils__/mocks.ts | 197 ++++++++- .../GitlabOrgDiscoveryEntityProvider.test.ts | 376 ++++++++---------- 4 files changed, 364 insertions(+), 221 deletions(-) diff --git a/.yarnrc.yml b/.yarnrc.yml index 18069eb1a7..466074db0a 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,17 +1,13 @@ enableGlobalCache: true -httpProxy: "http://sia-lb.telekom.de:8080" - httpTimeout: 300000 -httpsProxy: "http://sia-lb.telekom.de:8080" - nodeLinker: node-modules -npmRegistryServer: "https://registry.npmjs.org/" +npmRegistryServer: 'https://registry.npmjs.org/' plugins: - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs - spec: "@yarnpkg/plugin-workspace-tools" + spec: '@yarnpkg/plugin-workspace-tools' yarnPath: .yarn/releases/yarn-3.8.1.cjs diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index 04a95c4332..e49fb54465 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -19,6 +19,7 @@ import { all_groups_response, all_projects_response, all_saas_users_response, + all_self_hosted_group1_members, subgroup_saas_users_response, all_users_response, apiBaseUrl, @@ -64,6 +65,9 @@ const httpHandlers = [ rest.get(`${apiBaseUrl}/groups/42`, (_, res, ctx) => { return res(ctx.status(500), ctx.json({ error: 'Internal Server Error' })); }), + rest.get(`${apiBaseUrl}/groups/group1/members/all`, (_req, res, ctx) => { + return res(ctx.json(all_self_hosted_group1_members)); + }), rest.get(`${apiBaseUrlSaas}/groups/group1/members/all`, (_req, res, ctx) => { return res(ctx.json(all_saas_users_response)); diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts index b30f80888f..798df32695 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts @@ -596,6 +596,127 @@ export const config_org_double_integration: MockObject = { }, }; +export const config_org_group_saas = { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, +}; + +export const config_org_group_restrictUsers_false_saas = { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, +}; + +export const config_org_group_restrictUsers_true_saas = { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1/subgroup1', + restrictUsersToGroup: true, + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, +}; + +export const config_org_group_selfHosted = { + integrations: { + gitlab: [ + { + host: 'example.com', + apiBaseUrl: 'https://example.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'example.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, +}; + +export const config_org_group_restrictUsers_true_selfHosted = { + integrations: { + gitlab: [ + { + host: 'example.com', + apiBaseUrl: 'https://example.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'example.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + restrictUsersToGroup: true, + }, + }, + }, + }, +}; /** * GitLab API responses */ @@ -1969,7 +2090,7 @@ export const expected_subgroup_org_scan_entities_saas: MockObject[] = [ ]; // Simulate return of all users but only with membership of the descendants of config.group -export const expected_group_org_scan_entities: MockObject[] = [ +export const expected_full_members_group_org_scan_entities: MockObject[] = [ { entity: { apiVersion: 'backstage.io/v1alpha1', @@ -2093,3 +2214,77 @@ export const expected_group_org_scan_entities: MockObject[] = [ locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, ]; + +export const expected_group_members_group_org_scan_entities: MockObject[] = [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://example.com/JohnDoe', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/JohnDoe', + 'example.com/user-login': 'https://gitlab.example/john_doe', + }, + name: 'JohnDoe', + }, + spec: { + memberOf: ['subgroup1'], + profile: { + displayName: 'John Doe', + email: 'john.doe@company.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://example.com/group1/subgroup1', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/group1/subgroup1', + 'example.com/team-path': 'group1/subgroup1', + }, + name: 'subgroup1', + description: 'description1', + }, + spec: { + children: [], + profile: { + displayName: 'subgroup1', + }, + type: 'team', + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, +]; + +export const all_self_hosted_group1_members: MockObject[] = [ + { + id: 1, + username: 'JohnDoe', + name: 'John Doe', + state: 'active', + email: 'john.doe@company.com', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.example/john_doe', + }, + // inactive + { + id: 5, + username: 'MarioMario', + name: 'Mario Mario', + state: 'inactive', + email: 'mario.mario-company.com', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.example/mario_mario', + }, +]; 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 8cf046909d..ddc0d03570 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -175,220 +175,6 @@ describe('GitlabOrgDiscoveryEntityProvider - configuration', () => { }); }); -// This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas -it('SaaS: should get all saas root group users when restrictUsersToGroup is not set', async () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - apiBaseUrl: 'https://gitlab.com/api/v4', - token: '1234', - }, - ], - }, - catalog: { - providers: { - gitlab: { - 'test-id': { - host: 'gitlab.com', - group: 'group1', - orgEnabled: true, - skipForkedRepos: true, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_full_org_scan_entities_saas, // - }); -}); - -// This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas -it('SaaS: should get all saas root group users when restrictUsersToGroup is false', async () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - apiBaseUrl: 'https://gitlab.com/api/v4', - token: '1234', - }, - ], - }, - catalog: { - providers: { - gitlab: { - 'test-id': { - host: 'gitlab.com', - group: 'group1', - orgEnabled: true, - skipForkedRepos: true, - restrictUsersToGroup: false, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_full_org_scan_entities_saas, // - }); -}); - -// This should return only members of the SaaS subgroup (group1/subgroup1) -> expected_subgroup_org_scan_entities_saas -it('SaaS: should get only subgroup users when restrictUsersToGroup is true', async () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - apiBaseUrl: 'https://gitlab.com/api/v4', - token: '1234', - }, - ], - }, - catalog: { - providers: { - gitlab: { - 'test-id': { - host: 'gitlab.com', - group: 'group1/subgroup1', - restrictUsersToGroup: true, - orgEnabled: true, - skipForkedRepos: true, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_subgroup_org_scan_entities_saas, - }); -}); - -// This should return all members of the self-hosted instance regardless of the group set -> expected_full_org_scan_entities -it('Self-hosted: should get all instance users when restrictUsersToGroup is not set', async () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'example.com', - apiBaseUrl: 'https://example.com/api/v4', - token: '1234', - }, - ], - }, - catalog: { - providers: { - gitlab: { - 'test-id': { - host: 'example.com', - group: 'group1', - orgEnabled: true, - skipForkedRepos: true, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_group_org_scan_entities, // This should deliver all users but only their membership in subgroups of config.group - }); -}); - describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { it('should apply full update on scheduled execution', async () => { const config = new ConfigReader(mock.config_org_integration); @@ -516,6 +302,168 @@ describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { entities: mock.expected_full_org_scan_entities_saas, }); }); + + // This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas + it('SaaS: should get all saas root group users when restrictUsersToGroup is not set', async () => { + const config = new ConfigReader(mock.config_org_group_saas); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_org_scan_entities_saas, // + }); + }); + + // This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas + it('SaaS: should get all saas root group users when restrictUsersToGroup is false', async () => { + const config = new ConfigReader( + mock.config_org_group_restrictUsers_false_saas, + ); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_org_scan_entities_saas, // + }); + }); + + // This should return only members of the SaaS subgroup (group1/subgroup1) -> expected_subgroup_org_scan_entities_saas + it('SaaS: should get only subgroup users when restrictUsersToGroup is true', async () => { + const config = new ConfigReader( + mock.config_org_group_restrictUsers_true_saas, + ); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_subgroup_org_scan_entities_saas, + }); + }); + + // This should return all members of the self-hosted instance regardless of the group set -> expected_full_members_group_org_scan_entities + // All instance members, but only the group entities below the config.group + it('Self-hosted: should get all instance users when restrictUsersToGroup is not set', async () => { + const config = new ConfigReader(mock.config_org_group_selfHosted); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_members_group_org_scan_entities, // This should deliver all users but only their membership in subgroups of config.group + }); + }); + + // This should return all members of the self-hosted config.group and all group entities of config.group -> expected_full_members_group_org_scan_entities + it('Self-hosted: should get only groups users when restrictUsersToGroup is set', async () => { + const config = new ConfigReader( + mock.config_org_group_restrictUsers_true_selfHosted, + ); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_group_members_group_org_scan_entities, // This should deliver all users but only their membership in subgroups of config.group + }); + }); }); describe('GitlabOrgDiscoveryEntityProvider with events support', () => { From 206698c3115bfcc40c49a82c08e15ed67b170bbb Mon Sep 17 00:00:00 2001 From: Hghtwr Date: Fri, 21 Jun 2024 10:02:15 +0200 Subject: [PATCH 176/860] revert EntityProvider signature Signed-off-by: Hghtwr --- .../src/providers/GitlabOrgDiscoveryEntityProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index e2043e0393..d525e3290c 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -107,7 +107,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { private userTransformer: UserTransformer; private groupEntitiesTransformer: GroupEntitiesTransformer; private groupNameTransformer: GroupNameTransformer; - public readonly gitLabClient: GitLabClient; + private readonly gitLabClient: GitLabClient; static fromConfig( config: Config, From 6f8e1176d858545ade3340a656bd098f25113c10 Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Fri, 21 Jun 2024 12:30:17 +0100 Subject: [PATCH 177/860] 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 178/860] 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 e2e320cac00ab7e511bb58c8a299a5b2f9b35bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20V=C4=82LCIU?= Date: Thu, 20 Jun 2024 19:16:42 +0300 Subject: [PATCH 179/860] backstage-cli (templates): update dependencies of the backend plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove unneeded dependencies `winston` and `yn` from the template of backend plugins; * use `msw` v2 on the backend plugins; migrating later from v1 to v2 is not straight forward; it is better to start with v2; Signed-off-by: Valentin VĂLCIU --- .changeset/friendly-stingrays-occur.md | 7 +++++++ .../cli/templates/default-backend-plugin/package.json.hbs | 6 ++---- 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .changeset/friendly-stingrays-occur.md diff --git a/.changeset/friendly-stingrays-occur.md b/.changeset/friendly-stingrays-occur.md new file mode 100644 index 0000000000..3383203b40 --- /dev/null +++ b/.changeset/friendly-stingrays-occur.md @@ -0,0 +1,7 @@ +--- +'@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/packages/cli/templates/default-backend-plugin/package.json.hbs b/packages/cli/templates/default-backend-plugin/package.json.hbs index 6b7aa915aa..c20a1854a2 100644 --- a/packages/cli/templates/default-backend-plugin/package.json.hbs +++ b/packages/cli/templates/default-backend-plugin/package.json.hbs @@ -35,9 +35,7 @@ "@types/express": "{{versionQuery '@types/express' '4.17.6'}}", "express": "{{versionQuery 'express' '4.17.1'}}", "express-promise-router": "{{versionQuery 'express-promise-router' '4.1.0'}}", - "winston": "{{versionQuery 'winston' '3.2.1'}}", - "node-fetch": "{{versionQuery 'node-fetch' '2.6.7'}}", - "yn": "{{versionQuery 'yn' '4.0.0'}}" + "node-fetch": "{{versionQuery 'node-fetch' '2.6.7'}}" }, "devDependencies": { "@backstage/cli": "{{versionQuery '@backstage/cli'}}", @@ -45,7 +43,7 @@ "@backstage/plugin-auth-backend-module-guest-provider": "{{versionQuery '@backstage/plugin-auth-backend-module-guest-provider'}}", "@types/supertest": "{{versionQuery '@types/supertest' '2.0.12'}}", "supertest": "{{versionQuery 'supertest' '6.2.4'}}", - "msw": "{{versionQuery 'msw' '1.0.0'}}" + "msw": "{{versionQuery 'msw' '2.3.1'}}" }, "files": [ "dist" From d7773d174b3b4fab95db812d6a65cb7bff064139 Mon Sep 17 00:00:00 2001 From: Patrick Jungermann Date: Fri, 21 Jun 2024 22:30:44 +0200 Subject: [PATCH 180/860] 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 181/860] 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 89c44b36544499ac1fe4c04f165abf7b603d4a9c Mon Sep 17 00:00:00 2001 From: Matt Benson Date: Fri, 21 Jun 2024 19:23:44 -0500 Subject: [PATCH 182/860] Support catalogFilter array on OwnedEntityPicker; addresses https://github.com/backstage/backstage/issues/25358 Signed-off-by: Matt Benson --- .changeset/silent-moose-eat.md | 5 ++++ .../OwnedEntityPicker/OwnedEntityPicker.tsx | 23 ++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 .changeset/silent-moose-eat.md diff --git a/.changeset/silent-moose-eat.md b/.changeset/silent-moose-eat.md new file mode 100644 index 0000000000..735afa12f1 --- /dev/null +++ b/.changeset/silent-moose-eat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Support catalogFilter array on OwnedEntityPicker diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index d5351d54e5..02c437ceb6 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -90,17 +90,11 @@ function buildEntityPickerUISchema( uiSchema?.['ui:options'] || {}; const allowedKinds = uiOptions.allowedKinds; - const catalogFilter = { - ...uiOptions.catalogFilter, - ...(allowedKinds - ? { - kind: allowedKinds, - [`relations.${RELATION_OWNED_BY}`]: identityRefs || [], - } - : { - [`relations.${RELATION_OWNED_BY}`]: identityRefs || [], - }), - }; + const catalogFilter = asArray(uiOptions.catalogFilter).map(e => ({ + ...e, + ...(allowedKinds ? { kind: allowedKinds } : {}), + [`relations.${RELATION_OWNED_BY}`]: identityRefs || [], + })); return { 'ui:options': { @@ -108,3 +102,10 @@ function buildEntityPickerUISchema( }, }; } + +function asArray(catalogFilter: any): any[] { + if (catalogFilter) { + return Array.isArray(catalogFilter) ? catalogFilter : [catalogFilter]; + } + return [{}]; +} From c17cf4fd23556921f54afe9738162e5750bbfa86 Mon Sep 17 00:00:00 2001 From: John Philip Date: Sat, 22 Jun 2024 13:00:35 -0400 Subject: [PATCH 183/860] add publisher extension point Signed-off-by: John Philip --- plugins/techdocs-backend/src/plugin.ts | 14 ++++ plugins/techdocs-node/src/extensions.ts | 27 +++++- plugins/techdocs-node/src/index.ts | 2 + .../src/stages/publish/publish.test.ts | 17 ++++ .../src/stages/publish/publish.ts | 83 +++++++++++++++++-- .../techdocs-node/src/stages/publish/types.ts | 11 +++ 6 files changed, 144 insertions(+), 10 deletions(-) diff --git a/plugins/techdocs-backend/src/plugin.ts b/plugins/techdocs-backend/src/plugin.ts index 094335a0f0..1b495bafee 100644 --- a/plugins/techdocs-backend/src/plugin.ts +++ b/plugins/techdocs-backend/src/plugin.ts @@ -30,11 +30,14 @@ import { PreparerBase, Preparers, Publisher, + PublisherBase, + PublisherType, RemoteProtocol, techdocsBuildsExtensionPoint, TechdocsGenerator, techdocsGeneratorExtensionPoint, techdocsPreparerExtensionPoint, + techdocsPublisherExtensionPoint, } from '@backstage/plugin-techdocs-node'; import Docker from 'dockerode'; import { createRouter } from '@backstage/plugin-techdocs-backend'; @@ -87,6 +90,16 @@ export const techdocsPlugin = createBackendPlugin({ }, }); + let customTechdocsPublisher: PublisherBase | undefined; + env.registerExtensionPoint(techdocsPublisherExtensionPoint, { + registerPublisher(type: PublisherType, publisher: PublisherBase) { + if (customTechdocsPublisher) { + throw new Error(`Publisher for type ${type} is already registered`); + } + customTechdocsPublisher = publisher; + }, + }); + env.registerInit({ deps: { config: coreServices.rootConfig, @@ -135,6 +148,7 @@ export const techdocsPlugin = createBackendPlugin({ const publisher = await Publisher.fromConfig(config, { logger: winstonLogger, discovery: discovery, + customPublisher: customTechdocsPublisher, }); // checks if the publisher is working and logs the result diff --git a/plugins/techdocs-node/src/extensions.ts b/plugins/techdocs-node/src/extensions.ts index 8e7c9ef244..c32a0d2db5 100644 --- a/plugins/techdocs-node/src/extensions.ts +++ b/plugins/techdocs-node/src/extensions.ts @@ -15,7 +15,13 @@ */ import { createExtensionPoint } from '@backstage/backend-plugin-api'; import { DocsBuildStrategy } from './techdocsTypes'; -import { PreparerBase, RemoteProtocol, TechdocsGenerator } from './stages'; +import { + PreparerBase, + PublisherBase, + PublisherType, + RemoteProtocol, + TechdocsGenerator, +} from './stages'; import * as winston from 'winston'; /** @@ -75,3 +81,22 @@ export const techdocsPreparerExtensionPoint = createExtensionPoint({ id: 'techdocs.preparer', }); + +/** + * Extension point type for configuring a custom Techdocs publisher + * + * @public + */ +export interface TechdocsPublisherExtensionPoint { + registerPublisher(type: PublisherType, publisher: PublisherBase): void; +} + +/** + * Extension point for configuring a custom Techdocs publisher + * + * @public + */ +export const techdocsPublisherExtensionPoint = + createExtensionPoint({ + id: 'techdocs.publisher', + }); diff --git a/plugins/techdocs-node/src/index.ts b/plugins/techdocs-node/src/index.ts index b2efadf423..18f15f39ce 100644 --- a/plugins/techdocs-node/src/index.ts +++ b/plugins/techdocs-node/src/index.ts @@ -27,7 +27,9 @@ export { techdocsBuildsExtensionPoint, techdocsGeneratorExtensionPoint, techdocsPreparerExtensionPoint, + techdocsPublisherExtensionPoint, type TechdocsBuildsExtensionPoint, type TechdocsGeneratorExtensionPoint, type TechdocsPreparerExtensionPoint, + type TechdocsPublisherExtensionPoint, } from './extensions'; diff --git a/plugins/techdocs-node/src/stages/publish/publish.test.ts b/plugins/techdocs-node/src/stages/publish/publish.test.ts index 4059eccfeb..0063839e2f 100644 --- a/plugins/techdocs-node/src/stages/publish/publish.test.ts +++ b/plugins/techdocs-node/src/stages/publish/publish.test.ts @@ -25,6 +25,7 @@ import { AwsS3Publish } from './awsS3'; import { AzureBlobStoragePublish } from './azureBlobStorage'; import { OpenStackSwiftPublish } from './openStackSwift'; import { mockServices } from '@backstage/backend-test-utils'; +import { PublisherBase } from './types'; const logger = loggerToWinstonLogger(mockServices.logger.mock()); const discovery: jest.Mocked = { @@ -184,4 +185,20 @@ describe('Publisher', () => { }); expect(publisher).toBeInstanceOf(OpenStackSwiftPublish); }); + + it('registers a custom publisher if provided', async () => { + const mockConfig = new ConfigReader({}); + + const customPublisher = { + publish: jest.fn(), + } as unknown as PublisherBase; + + const publisher = await Publisher.fromConfig(mockConfig, { + logger, + discovery, + customPublisher, + }); + + expect(publisher).toBe(customPublisher); + }); }); diff --git a/plugins/techdocs-node/src/stages/publish/publish.ts b/plugins/techdocs-node/src/stages/publish/publish.ts index 732b161b42..4fb731a0ba 100644 --- a/plugins/techdocs-node/src/stages/publish/publish.ts +++ b/plugins/techdocs-node/src/stages/publish/publish.ts @@ -20,14 +20,47 @@ import { AzureBlobStoragePublish } from './azureBlobStorage'; import { GoogleGCSPublish } from './googleStorage'; import { LocalPublish } from './local'; import { OpenStackSwiftPublish } from './openStackSwift'; -import { PublisherFactory, PublisherBase, PublisherType } from './types'; +import { + PublisherFactory, + PublisherBase, + PublisherType, + PublisherBuilder, +} from './types'; /** * Factory class to create a TechDocs publisher based on defined publisher type in app config. * Uses `techdocs.publisher.type`. * @public */ -export class Publisher { + +type CustomPublisherType = PublisherType | 'techdocs'; + +export class Publisher implements PublisherBuilder { + private publishers: Map = new Map(); + + register(type: CustomPublisherType, publisher: PublisherBase): void { + this.publishers.set(type, publisher); + } + + get(config: Config): PublisherBase { + const publisherType = (config.getOptionalString( + 'techdocs.publisher.type', + ) ?? 'local') as PublisherType; + + if (!publisherType) { + throw new Error('TechDocs publisher type not specified for the entity'); + } + + const publisher = this.publishers.get(publisherType); + if (!publisher) { + throw new Error( + `TechDocs publisher '${publisherType}' is not registered`, + ); + } + + return publisher; + } + /** * Returns a instance of TechDocs publisher * @param config - A Backstage configuration @@ -37,7 +70,14 @@ export class Publisher { config: Config, options: PublisherFactory, ): Promise { - const { logger, discovery } = options; + const { logger, discovery, customPublisher } = options; + + const publishers = new Publisher(); + + if (customPublisher) { + publishers.register('techdocs', customPublisher); + return customPublisher; + } const publisherType = (config.getOptionalString( 'techdocs.publisher.type', @@ -46,26 +86,51 @@ export class Publisher { switch (publisherType) { case 'googleGcs': logger.info('Creating Google Storage Bucket publisher for TechDocs'); - return GoogleGCSPublish.fromConfig(config, logger); + publishers.register( + publisherType, + GoogleGCSPublish.fromConfig(config, logger), + ); + break; case 'awsS3': logger.info('Creating AWS S3 Bucket publisher for TechDocs'); - return await AwsS3Publish.fromConfig(config, logger); + publishers.register( + publisherType, + await AwsS3Publish.fromConfig(config, logger), + ); + break; case 'azureBlobStorage': logger.info( 'Creating Azure Blob Storage Container publisher for TechDocs', ); - return AzureBlobStoragePublish.fromConfig(config, logger); + publishers.register( + publisherType, + AzureBlobStoragePublish.fromConfig(config, logger), + ); + break; case 'openStackSwift': logger.info( 'Creating OpenStack Swift Container publisher for TechDocs', ); - return OpenStackSwiftPublish.fromConfig(config, logger); + publishers.register( + publisherType, + OpenStackSwiftPublish.fromConfig(config, logger), + ); + break; case 'local': logger.info('Creating Local publisher for TechDocs'); - return LocalPublish.fromConfig(config, logger, discovery); + publishers.register( + publisherType, + LocalPublish.fromConfig(config, logger, discovery), + ); + break; default: logger.info('Creating Local publisher for TechDocs'); - return LocalPublish.fromConfig(config, logger, discovery); + publishers.register( + publisherType, + LocalPublish.fromConfig(config, logger, discovery), + ); } + + return publishers.get(config); } } diff --git a/plugins/techdocs-node/src/stages/publish/types.ts b/plugins/techdocs-node/src/stages/publish/types.ts index ff5b9acade..3acd48a468 100644 --- a/plugins/techdocs-node/src/stages/publish/types.ts +++ b/plugins/techdocs-node/src/stages/publish/types.ts @@ -17,6 +17,7 @@ import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { Logger } from 'winston'; import express from 'express'; +import { Config } from '@backstage/config'; /** * Options for building publishers @@ -25,6 +26,7 @@ import express from 'express'; export type PublisherFactory = { logger: Logger; discovery: PluginEndpointDiscovery; + customPublisher?: PublisherBase | undefined; }; /** @@ -157,3 +159,12 @@ export interface PublisherBase { */ migrateDocsCase?(migrateRequest: MigrateRequest): Promise; } + +/** + * Definition for a TechDocs publisher builder + * @public + */ +export type PublisherBuilder = { + register(type: PublisherType, publisher: PublisherBase): void; + get(config: Config): PublisherBase; +}; From 9ecf5fdcb9b66b97b0cb8604b7358eaf6a2bb18c Mon Sep 17 00:00:00 2001 From: John Philip Date: Sat, 22 Jun 2024 13:04:19 -0400 Subject: [PATCH 184/860] add changeset Signed-off-by: John Philip --- .changeset/fair-fans-flow.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/fair-fans-flow.md diff --git a/.changeset/fair-fans-flow.md b/.changeset/fair-fans-flow.md new file mode 100644 index 0000000000..abdc22440b --- /dev/null +++ b/.changeset/fair-fans-flow.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-techdocs-node': patch +--- + +Adds extension point for publishers to the techdocs backend From 4c4d077b9abb1fa2840768072f7a291340bc2dd9 Mon Sep 17 00:00:00 2001 From: John Philip Date: Sat, 22 Jun 2024 13:10:45 -0400 Subject: [PATCH 185/860] add changeset Signed-off-by: John Philip --- .changeset/neat-dingos-tickle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/neat-dingos-tickle.md diff --git a/.changeset/neat-dingos-tickle.md b/.changeset/neat-dingos-tickle.md new file mode 100644 index 0000000000..43929e532f --- /dev/null +++ b/.changeset/neat-dingos-tickle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': patch +--- + +Bumps default version of techdocs docker image to latest From e10c75aebfdc030ea3dac888ac165d93cd75d032 Mon Sep 17 00:00:00 2001 From: "Stephen A. Wilson" Date: Sat, 22 Jun 2024 15:52:58 -0400 Subject: [PATCH 186/860] 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 fea739f1caa1987c9edce53bd6398a6da1504dd0 Mon Sep 17 00:00:00 2001 From: John Philip Date: Sat, 22 Jun 2024 21:14:24 -0400 Subject: [PATCH 187/860] fix api reports Signed-off-by: John Philip --- plugins/techdocs-node/api-report.md | 22 ++++++++++++++++++- .../techdocs-node/src/stages/publish/index.ts | 1 + .../src/stages/publish/publish.ts | 8 +++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/plugins/techdocs-node/api-report.md b/plugins/techdocs-node/api-report.md index 2d3ca90983..364c6dade0 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -183,11 +183,15 @@ export class Preparers implements PreparerBuilder { } // @public -export class Publisher { +export class Publisher implements PublisherBuilder { static fromConfig( config: Config, options: PublisherFactory, ): Promise; + // (undocumented) + get(config: Config): PublisherBase; + // (undocumented) + register(type: PublisherType | 'techdocs', publisher: PublisherBase): void; } // @public @@ -202,10 +206,17 @@ export interface PublisherBase { publish(request: PublishRequest): Promise; } +// @public +export type PublisherBuilder = { + register(type: PublisherType, publisher: PublisherBase): void; + get(config: Config): PublisherBase; +}; + // @public export type PublisherFactory = { logger: Logger; discovery: PluginEndpointDiscovery; + customPublisher?: PublisherBase | undefined; }; // @public @@ -303,6 +314,15 @@ export interface TechdocsPreparerExtensionPoint { // @public export const techdocsPreparerExtensionPoint: ExtensionPoint; +// @public +export interface TechdocsPublisherExtensionPoint { + // (undocumented) + registerPublisher(type: PublisherType, publisher: PublisherBase): void; +} + +// @public +export const techdocsPublisherExtensionPoint: ExtensionPoint; + // @public export const transformDirLocation: ( entity: Entity, diff --git a/plugins/techdocs-node/src/stages/publish/index.ts b/plugins/techdocs-node/src/stages/publish/index.ts index c6f86f6bc1..f342ccf0ae 100644 --- a/plugins/techdocs-node/src/stages/publish/index.ts +++ b/plugins/techdocs-node/src/stages/publish/index.ts @@ -23,4 +23,5 @@ export type { MigrateRequest, ReadinessResponse, TechDocsMetadata, + PublisherBuilder, } from './types'; diff --git a/plugins/techdocs-node/src/stages/publish/publish.ts b/plugins/techdocs-node/src/stages/publish/publish.ts index 4fb731a0ba..09a6d9b375 100644 --- a/plugins/techdocs-node/src/stages/publish/publish.ts +++ b/plugins/techdocs-node/src/stages/publish/publish.ts @@ -32,13 +32,11 @@ import { * Uses `techdocs.publisher.type`. * @public */ - -type CustomPublisherType = PublisherType | 'techdocs'; - export class Publisher implements PublisherBuilder { - private publishers: Map = new Map(); + private publishers: Map = + new Map(); - register(type: CustomPublisherType, publisher: PublisherBase): void { + register(type: PublisherType | 'techdocs', publisher: PublisherBase): void { this.publishers.set(type, publisher); } From 897afcc4d560d08d9001e0413c4dd49134cfdcfc Mon Sep 17 00:00:00 2001 From: John Philip Date: Sat, 22 Jun 2024 22:45:29 -0400 Subject: [PATCH 188/860] fix api reports Signed-off-by: John Philip --- plugins/techdocs-node/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/techdocs-node/api-report.md b/plugins/techdocs-node/api-report.md index 3966b7d2d8..0b30170006 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -268,7 +268,7 @@ export class TechdocsGenerator implements GeneratorBase { config: Config; scmIntegrations: ScmIntegrationRegistry; }); - static readonly defaultDockerImage = 'spotify/techdocs:v1.2.3'; + static readonly defaultDockerImage = 'spotify/techdocs:v1.2.4'; static fromConfig( config: Config, options: GeneratorOptions, From ed2786f9f8d5e8699325b2605e6fd32eeac1f2f5 Mon Sep 17 00:00:00 2001 From: Antonio Ereiz Date: Sun, 23 Jun 2024 21:04:03 +0200 Subject: [PATCH 189/860] add comment Signed-off-by: Antonio Ereiz --- docs/tutorials/setup-opentelemetry.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorials/setup-opentelemetry.md b/docs/tutorials/setup-opentelemetry.md index 30dde79db8..7034e99b4c 100644 --- a/docs/tutorials/setup-opentelemetry.md +++ b/docs/tutorials/setup-opentelemetry.md @@ -33,6 +33,7 @@ const { } = require('@opentelemetry/auto-instrumentations-node'); const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); +// By default exports the metrics on port 9464 const prometheus = new PrometheusExporter(); const sdk = new NodeSDK({ // You can add a traceExporter field here too From 09c6d445127dd7858a37a58b4b9364f2d8950a2f Mon Sep 17 00:00:00 2001 From: Antonio Ereiz Date: Sun, 23 Jun 2024 21:09:39 +0200 Subject: [PATCH 190/860] 'edit' Signed-off-by: Antonio Ereiz --- docs/tutorials/setup-opentelemetry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/setup-opentelemetry.md b/docs/tutorials/setup-opentelemetry.md index 7034e99b4c..faaeab49f4 100644 --- a/docs/tutorials/setup-opentelemetry.md +++ b/docs/tutorials/setup-opentelemetry.md @@ -33,7 +33,7 @@ const { } = require('@opentelemetry/auto-instrumentations-node'); const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); -// By default exports the metrics on port 9464 +// By default exports the metrics on localhost:9464/metrics const prometheus = new PrometheusExporter(); const sdk = new NodeSDK({ // You can add a traceExporter field here too From 01999b3c78944af74640c2f1c9737399b3c8a2f3 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 24 Jun 2024 10:49:49 +0200 Subject: [PATCH 191/860] chore: enter pre Signed-off-by: blam --- .changeset/pre.json | 190 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..dcb909ba99 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,190 @@ +{ + "mode": "pre", + "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" + }, + "changesets": [] +} From acda33a75293ff1966a3e1aa3b239e6d32864b34 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 24 Jun 2024 11:21:34 +0200 Subject: [PATCH 192/860] chore: update yarn.lock Signed-off-by: blam --- yarn.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn.lock b/yarn.lock index f81ce9dabd..225004ba7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6829,6 +6829,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" + "@backstage/plugin-bitbucket-cloud-common": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" fs-extra: ^11.2.0 From 0273ae27d34bdf393b10321525d98a837abf3084 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 24 Jun 2024 11:52:39 +0200 Subject: [PATCH 193/860] feat: fix tests and test confifmr Signed-off-by: blam --- .../src/autocomplete/autocomplete.test.ts | 48 ++++++++--- plugins/scaffolder-backend/package.json | 1 + .../src/service/router.test.ts | 80 +++++++++++++++---- .../scaffolder-backend/src/service/router.ts | 1 + yarn.lock | 1 + 5 files changed, 102 insertions(+), 29 deletions(-) diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts index 50e218ce85..7367504d93 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts @@ -43,7 +43,11 @@ describe('handleAutocompleteRequest', () => { it('should pass the token to the client', async () => { const accessToken = 'foo'; - await handleAutocompleteRequest(accessToken, 'workspaces', {}); + await handleAutocompleteRequest({ + token: accessToken, + context: {}, + resource: 'workspaces', + }); expect(fromConfig).toHaveBeenCalledWith( expect.objectContaining({ accessToken }), @@ -51,37 +55,57 @@ describe('handleAutocompleteRequest', () => { }); it('should return workspaces', async () => { - const result = await handleAutocompleteRequest('foo', 'workspaces', {}); + const result = await handleAutocompleteRequest({ + token: 'foo', + context: {}, + resource: 'workspaces', + }); - expect(result).toEqual(['workspace1']); + expect(result).toEqual({ results: [{ title: 'workspace1' }] }); }); it('should return projects', async () => { - const result = await handleAutocompleteRequest('foo', 'projects', { - workspace: 'workspace1', + const result = await handleAutocompleteRequest({ + token: 'foo', + context: { + workspace: 'workspace1', + }, + resource: 'projects', }); - expect(result).toEqual(['project1']); + expect(result).toEqual({ results: [{ title: 'project1' }] }); }); it('should return repositories', async () => { - const result = await handleAutocompleteRequest('foo', 'repositories', { - workspace: 'workspace1', - project: 'project1', + const result = await handleAutocompleteRequest({ + token: 'foo', + resource: 'repositories', + context: { + workspace: 'workspace1', + project: 'project1', + }, }); - expect(result).toEqual(['repository1']); + expect(result).toEqual({ results: [{ title: 'repository1' }] }); }); it('should throw an error when passing an invalid resource', async () => { await expect( - handleAutocompleteRequest('token', 'invalid', {}), + handleAutocompleteRequest({ + token: 'token', + resource: 'invalid', + context: {}, + }), ).rejects.toThrow(InputError); }); it('should throw an error when there are missing parameters', async () => { await expect( - handleAutocompleteRequest('token', 'projects', {}), + handleAutocompleteRequest({ + token: 'token', + resource: 'projects', + context: {}, + }), ).rejects.toThrow(InputError); }); }); diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index af6625c8b8..eb977787c2 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -114,6 +114,7 @@ "zod": "^3.22.4" }, "devDependencies": { + "@backstage/backend-app-api": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-scaffolder-node-test-utils": "workspace:^", diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 4bd3847666..f0e78c75c7 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -46,6 +46,8 @@ import { PermissionEvaluator, } from '@backstage/plugin-permission-common'; import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; +import { AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; +import { MiddlewareFactory } from '@backstage/backend-app-api'; const mockAccess = jest.fn(); @@ -62,8 +64,6 @@ jest.mock('fs-extra', () => ({ remove: jest.fn(), })); -jest.mock('./autocomplete'); - function createDatabase(): PluginDatabaseManager { return DatabaseManager.fromConfig( new ConfigReader({ @@ -1465,26 +1465,72 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ }); describe('GET /v2/autocomplete/:provider/:resource', () => { - it('should handle requests for provider bitbucketCloud', async () => { - jest - .mocked(handleBitbucketCloudRequest) - .mockResolvedValue(['resource1']); + let handleAutocompleteRequest: AutocompleteHandler; - const bbToken = 'foo'; - const resource = 'bar'; + beforeEach(async () => { + handleAutocompleteRequest = jest.fn().mockResolvedValue({ + results: [{ title: 'blob' }], + }); + + const logger = mockServices.logger.mock(); + const middleware = MiddlewareFactory.create({ config, logger }); + const router = await createRouter({ + logger: loggerToWinstonLogger(mockServices.logger.mock()), + config: new ConfigReader({}), + database: createDatabase(), + catalogClient, + reader: mockUrlReader, + taskBroker, + permissions: permissionApi, + auth, + httpAuth, + discovery, + autocompleteHandlers: { + 'test-provider': handleAutocompleteRequest, + }, + }); + + app = express().use(router).use(middleware.error()); + }); + + it('should throw an error when the provider is not registered', async () => { + const response = await request(app) + .post('/v2/autocomplete/unknown-provider/resource') + .send({ + token: 'token', + context: {}, + }); + + expect(response.status).toEqual(400); + expect(response.body).toEqual( + expect.objectContaining({ + error: { + message: 'Unsupported provider: unknown-provider', + name: 'InputError', + }, + }), + ); + }); + + it('should call the autocomplete handler', async () => { + const context = { mock: 'context' }; + const mockToken = 'mocktoken'; const response = await request(app) - .get(`/v2/autocomplete/bitbucketCloud/${resource}`) - .query({ token: bbToken, workspace: 'workspace1' }); - - expect(handleBitbucketCloudRequest).toHaveBeenCalledWith( - bbToken, - resource, - { workspace: 'workspace1' }, - ); + .post('/v2/autocomplete/test-provider/resource') + .send({ + token: mockToken, + context, + }); expect(response.status).toEqual(200); - expect(response.body).toEqual(['resource1']); + + expect(response.body).toEqual({ results: [{ title: 'blob' }] }); + expect(handleAutocompleteRequest).toHaveBeenCalledWith({ + token: mockToken, + context, + resource: 'resource', + }); }); }); }); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index e5f88c3482..9b3f5173c8 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -785,6 +785,7 @@ export async function createRouter( if (!autocompleteHandlers[provider]) { throw new InputError(`Unsupported provider: ${provider}`); } + const { results } = await autocompleteHandlers[provider]({ resource, token, diff --git a/yarn.lock b/yarn.lock index 225004ba7a..9952ad2bbd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7083,6 +7083,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-scaffolder-backend@workspace:plugins/scaffolder-backend" dependencies: + "@backstage/backend-app-api": "workspace:^" "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^" From db2bdce0a0cac75fb87dfc26566453e3c404cd46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C4=85tkiewicz?= Date: Mon, 24 Jun 2024 11:59:31 +0200 Subject: [PATCH 194/860] Update discord channel name in README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piotr Piątkiewicz --- docs/features/techdocs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/techdocs/README.md b/docs/features/techdocs/README.md index a696b850a8..beec6d1fad 100644 --- a/docs/features/techdocs/README.md +++ b/docs/features/techdocs/README.md @@ -102,7 +102,7 @@ See [TechDocs Architecture](architecture.md) to get an overview of where the bel ## Get involved -Reach out to us in the **#docs-like-code** channel of our +Reach out to us in the **#techdocs** channel of our [Discord chatroom](https://github.com/backstage/backstage#community). ## Done From b8230e475399611128f969b2bd185842b1bf6fcc Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 12:59:04 +0200 Subject: [PATCH 195/860] feat: matching plugin type to output Signed-off-by: Alper Altay --- packages/cli/src/lib/new/factories/pluginCommon.test.ts | 2 +- packages/cli/src/lib/new/factories/pluginCommon.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/lib/new/factories/pluginCommon.test.ts b/packages/cli/src/lib/new/factories/pluginCommon.test.ts index d85e490510..82c1c87169 100644 --- a/packages/cli/src/lib/new/factories/pluginCommon.test.ts +++ b/packages/cli/src/lib/new/factories/pluginCommon.test.ts @@ -67,7 +67,7 @@ describe('pluginCommon factory', () => { expect(modified).toBe(true); expectLogsToMatch(output, [ - 'Creating backend plugin backstage-plugin-test-common', + 'Creating common plugin package backstage-plugin-test-common', 'Checking Prerequisites:', `availability plugins${sep}test-common`, 'creating temp dir', diff --git a/packages/cli/src/lib/new/factories/pluginCommon.ts b/packages/cli/src/lib/new/factories/pluginCommon.ts index 560386c618..5f694124ea 100644 --- a/packages/cli/src/lib/new/factories/pluginCommon.ts +++ b/packages/cli/src/lib/new/factories/pluginCommon.ts @@ -46,7 +46,7 @@ export const pluginCommon = createFactory({ }); Task.log(); - Task.log(`Creating backend plugin ${chalk.cyan(name)}`); + Task.log(`Creating common plugin package ${chalk.cyan(name)}`); const targetDir = ctx.isMonoRepo ? paths.resolveTargetRoot('plugins', suffix) From 0540c5a6c237f737d4a06af1abf74bf535dd1d98 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 13:07:34 +0200 Subject: [PATCH 196/860] feat: changeset Signed-off-by: Alper Altay --- .changeset/funny-laws-tease.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/funny-laws-tease.md diff --git a/.changeset/funny-laws-tease.md b/.changeset/funny-laws-tease.md new file mode 100644 index 0000000000..8ecbc87b65 --- /dev/null +++ b/.changeset/funny-laws-tease.md @@ -0,0 +1,5 @@ +--- +'@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...`. From b5a988f0c3a96973d3b667af6b976e0c0192f1c9 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 24 Jun 2024 13:10:55 +0200 Subject: [PATCH 197/860] chore: updating api-reports Signed-off-by: blam --- plugins/scaffolder-backend/api-report.md | 3 +++ plugins/scaffolder-node/api-report-alpha.md | 30 +++++++++++++++++++++ plugins/scaffolder-react/api-report.md | 16 ++++++----- plugins/scaffolder/api-report.md | 21 ++++++++++----- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 4c7b11ea43..4d75ed8421 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -7,6 +7,7 @@ import { ActionContext as ActionContext_2 } from '@backstage/plugin-scaffolder-node'; import { AuthService } from '@backstage/backend-plugin-api'; +import { AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; import * as azure from '@backstage/plugin-scaffolder-backend-module-azure'; import { BackstageCredentials } from '@backstage/backend-plugin-api'; import * as bitbucket from '@backstage/plugin-scaffolder-backend-module-bitbucket'; @@ -478,6 +479,8 @@ export interface RouterOptions { // (undocumented) auth?: AuthService; // (undocumented) + autocompleteHandlers?: Record; + // (undocumented) catalogClient: CatalogApi; concurrentTasksLimit?: number; // (undocumented) diff --git a/plugins/scaffolder-node/api-report-alpha.md b/plugins/scaffolder-node/api-report-alpha.md index c2a2a1597e..aae32d7203 100644 --- a/plugins/scaffolder-node/api-report-alpha.md +++ b/plugins/scaffolder-node/api-report-alpha.md @@ -9,6 +9,21 @@ import { TemplateAction } from '@backstage/plugin-scaffolder-node'; import { TemplateFilter } from '@backstage/plugin-scaffolder-node'; import { TemplateGlobal } from '@backstage/plugin-scaffolder-node'; +// @alpha +export type AutocompleteHandler = ({ + resource, + token, + context, +}: { + resource: string; + token: string; + context: Record; +}) => Promise<{ + results: { + title: string; + }[]; +}>; + // @alpha export interface ScaffolderActionsExtensionPoint { // (undocumented) @@ -18,6 +33,21 @@ export interface ScaffolderActionsExtensionPoint { // @alpha export const scaffolderActionsExtensionPoint: ExtensionPoint; +// @alpha +export interface ScaffolderAutocompleteExtensionPoint { + // (undocumented) + addAutocompleteProvider({ + id, + handler, + }: { + id: string; + handler: AutocompleteHandler; + }): void; +} + +// @alpha +export const scaffolderAutocompleteExtensionPoint: ExtensionPoint; + // @alpha export interface ScaffolderTaskBrokerExtensionPoint { // (undocumented) diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index cc6672a8a5..a14490b80c 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -180,12 +180,16 @@ export type ReviewStepProps = { // @public export interface ScaffolderApi { // (undocumented) - autocomplete( - token: string, - provider: string, - resource: string, - params?: Record, - ): Promise; + autocomplete?(options: { + token: string; + provider: string; + resource: string; + context?: Record; + }): Promise<{ + results: { + title: string; + }[]; + }>; cancelTask(taskId: string): Promise; // (undocumented) dryRun?(options: ScaffolderDryRunOptions): Promise; diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index affc69ed93..f479b13ec4 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -502,12 +502,21 @@ export class ScaffolderClient implements ScaffolderApi_2 { useLongPollingLogs?: boolean; }); // (undocumented) - autocomplete( - token: string, - provider: string, - resource: string, - params?: Record, - ): Promise; + autocomplete({ + token, + resource, + provider, + context, + }: { + token: string; + provider: string; + resource: string; + context?: Record; + }): Promise<{ + results: { + title: string; + }[]; + }>; // (undocumented) cancelTask(taskId: string): Promise; // (undocumented) From b5deed0c1ba6dc22581e2847a70edecee092fc52 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 24 Jun 2024 13:18:14 +0200 Subject: [PATCH 198/860] chore: updating changesets and api-reports Signed-off-by: blam --- .changeset/angry-ladybugs-retire.md | 5 ----- .changeset/five-forks-retire.md | 5 ----- .changeset/friendly-masks-type.md | 5 +++++ .changeset/great-colts-enjoy.md | 5 ----- .changeset/light-avocados-worry.md | 6 ++++++ .changeset/nine-seals-sit.md | 5 ----- .changeset/rare-planes-switch.md | 5 ----- .changeset/selfish-turtles-jog.md | 6 ++++++ .changeset/slimy-ties-relate.md | 5 ----- .changeset/tame-geese-run.md | 5 ----- .changeset/young-donuts-swim.md | 6 ++++++ packages/integration/api-report.md | 2 +- packages/integration/src/bitbucketCloud/config.ts | 2 +- plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts | 5 ++--- .../src/autocomplete/autocomplete.test.ts | 2 +- .../src/autocomplete/autocomplete.ts | 2 +- 16 files changed, 29 insertions(+), 42 deletions(-) delete mode 100644 .changeset/angry-ladybugs-retire.md delete mode 100644 .changeset/five-forks-retire.md create mode 100644 .changeset/friendly-masks-type.md delete mode 100644 .changeset/great-colts-enjoy.md create mode 100644 .changeset/light-avocados-worry.md delete mode 100644 .changeset/nine-seals-sit.md delete mode 100644 .changeset/rare-planes-switch.md create mode 100644 .changeset/selfish-turtles-jog.md delete mode 100644 .changeset/slimy-ties-relate.md delete mode 100644 .changeset/tame-geese-run.md create mode 100644 .changeset/young-donuts-swim.md diff --git a/.changeset/angry-ladybugs-retire.md b/.changeset/angry-ladybugs-retire.md deleted file mode 100644 index ca2b34676b..0000000000 --- a/.changeset/angry-ladybugs-retire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -Added autocompletion for Bitbucket Cloud diff --git a/.changeset/five-forks-retire.md b/.changeset/five-forks-retire.md deleted file mode 100644 index 9b9573bfd4..0000000000 --- a/.changeset/five-forks-retire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bitbucket-cloud-common': patch ---- - -Added support for access tokens diff --git a/.changeset/friendly-masks-type.md b/.changeset/friendly-masks-type.md new file mode 100644 index 0000000000..6f38ddefa3 --- /dev/null +++ b/.changeset/friendly-masks-type.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': minor +--- + +Add support for `token` for `bitbucketCloud` integration diff --git a/.changeset/great-colts-enjoy.md b/.changeset/great-colts-enjoy.md deleted file mode 100644 index 6907f661a5..0000000000 --- a/.changeset/great-colts-enjoy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bitbucket-cloud-common': patch ---- - -Added method `listProjectsByWorkspace` for retrieving projects by workspace diff --git a/.changeset/light-avocados-worry.md b/.changeset/light-avocados-worry.md new file mode 100644 index 0000000000..a3605a1451 --- /dev/null +++ b/.changeset/light-avocados-worry.md @@ -0,0 +1,6 @@ +--- +'@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/nine-seals-sit.md b/.changeset/nine-seals-sit.md deleted file mode 100644 index 0055a1be24..0000000000 --- a/.changeset/nine-seals-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': minor ---- - -Added support for access tokens to Bitbucket Cloud diff --git a/.changeset/rare-planes-switch.md b/.changeset/rare-planes-switch.md deleted file mode 100644 index 622c6d48d8..0000000000 --- a/.changeset/rare-planes-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bitbucket-cloud-common': patch ---- - -Added method `listWorkspaces` for retrieving workspaces diff --git a/.changeset/selfish-turtles-jog.md b/.changeset/selfish-turtles-jog.md new file mode 100644 index 0000000000..02506ec068 --- /dev/null +++ b/.changeset/selfish-turtles-jog.md @@ -0,0 +1,6 @@ +--- +'@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/slimy-ties-relate.md b/.changeset/slimy-ties-relate.md deleted file mode 100644 index d4da9972f1..0000000000 --- a/.changeset/slimy-ties-relate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Added endpoint for autocompleting provider resources (currently only supports Bitbucket) diff --git a/.changeset/tame-geese-run.md b/.changeset/tame-geese-run.md deleted file mode 100644 index 785ae6c7fc..0000000000 --- a/.changeset/tame-geese-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Added method `autocomplete` to interface `ScaffolderApi` diff --git a/.changeset/young-donuts-swim.md b/.changeset/young-donuts-swim.md new file mode 100644 index 0000000000..edd854f6dc --- /dev/null +++ b/.changeset/young-donuts-swim.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': minor +'@backstage/plugin-scaffolder': minor +--- + +Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` diff --git a/packages/integration/api-report.md b/packages/integration/api-report.md index 91abc7473f..4c8e8accf2 100644 --- a/packages/integration/api-report.md +++ b/packages/integration/api-report.md @@ -186,7 +186,7 @@ export type BitbucketCloudIntegrationConfig = { apiBaseUrl: string; username?: string; appPassword?: string; - accessToken?: string; + token?: string; }; // @public @deprecated diff --git a/packages/integration/src/bitbucketCloud/config.ts b/packages/integration/src/bitbucketCloud/config.ts index 2f533480cc..32a2af9313 100644 --- a/packages/integration/src/bitbucketCloud/config.ts +++ b/packages/integration/src/bitbucketCloud/config.ts @@ -50,7 +50,7 @@ export type BitbucketCloudIntegrationConfig = { /** * The access token to use for requests to Bitbucket Cloud (bitbucket.org). */ - accessToken?: string; + token?: string; }; /** diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts index a06f7425d0..f1b7d60e41 100644 --- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts +++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts @@ -139,11 +139,10 @@ export class BitbucketCloudClient { 'utf8', ); headers.Authorization = `Basic ${buffer.toString('base64')}`; + } else if (this.config.token) { + headers.Authorization = `Bearer ${this.config.token}`; } - if (this.config.accessToken) - headers.Authorization = `Bearer ${this.config.accessToken}`; - return headers; } } diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts index 7367504d93..0447ff2d28 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts @@ -50,7 +50,7 @@ describe('handleAutocompleteRequest', () => { }); expect(fromConfig).toHaveBeenCalledWith( - expect.objectContaining({ accessToken }), + expect.objectContaining({ token: accessToken }), ); }); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts index 50723fb41d..31a2103088 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts @@ -29,7 +29,7 @@ export async function handleAutocompleteRequest({ const client = BitbucketCloudClient.fromConfig({ host: 'bitbucket.org', apiBaseUrl: 'https://api.bitbucket.org/2.0', - accessToken: token, + token, }); switch (resource) { From cac042618a8f7f4ca7821d938ce9868c8baa7a40 Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:14:21 +0000 Subject: [PATCH 199/860] Added the HCE plugin to microsite Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> --- microsite/data/plugins/harness-chaos.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 microsite/data/plugins/harness-chaos.yaml diff --git a/microsite/data/plugins/harness-chaos.yaml b/microsite/data/plugins/harness-chaos.yaml new file mode 100644 index 0000000000..41254b5399 --- /dev/null +++ b/microsite/data/plugins/harness-chaos.yaml @@ -0,0 +1,12 @@ +title: Harness Service Reliability Management +author: harness.io +authorUrl: https://github.com/harness/backstage-plugins +category: Chaos Engineering +description: This plugin lets you view the status of Harness Chaos Engineering Resources and launch Chaos Experiments directly inside Backstage. +documentation: https://github.com/harness/backstage-plugins/tree/main/plugins/harness-chaos +iconUrl: https://static.harness.io/ng-static/images/favicon.png +npmPackageName: '@harnessio/backstage-plugin-harness-chaos' +tags: + - chaos-experiments + - resiliency +addedDate: '2024-06-25' \ No newline at end of file From 986199fe4cc277eaa4297d110f9c8ad81649154a Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:20:31 +0000 Subject: [PATCH 200/860] Added the HCE plugin to microsite Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> --- microsite/data/plugins/harness-chaos.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/microsite/data/plugins/harness-chaos.yaml b/microsite/data/plugins/harness-chaos.yaml index 41254b5399..563f29d6a1 100644 --- a/microsite/data/plugins/harness-chaos.yaml +++ b/microsite/data/plugins/harness-chaos.yaml @@ -9,4 +9,5 @@ npmPackageName: '@harnessio/backstage-plugin-harness-chaos' tags: - chaos-experiments - resiliency + - chaos-engineering addedDate: '2024-06-25' \ No newline at end of file From 04e657d4a083ccdaf948d29cc464c24654b89b15 Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:22:44 +0000 Subject: [PATCH 201/860] Added signoff Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> From 21c665cbd332efcfce84957dda347091feeecd98 Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:23:15 +0000 Subject: [PATCH 202/860] Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Added the sign-off Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> From 030f4b1549408947bd0f6d6bf6d4748f3b473d5b Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Mon, 24 Jun 2024 13:39:47 +0200 Subject: [PATCH 203/860] Update heavy-moose-pull.md Signed-off-by: blam --- .changeset/heavy-moose-pull.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/heavy-moose-pull.md b/.changeset/heavy-moose-pull.md index 7ba7b1aa39..86b2753a28 100644 --- a/.changeset/heavy-moose-pull.md +++ b/.changeset/heavy-moose-pull.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder': minor --- -Use virtualization with MultiEntityPicker. Fixes performance issues with large data sets. +Use virtualization with `MultiEntityPicker`. Fixes performance issues with large data sets. From c079fc184f8473d3eb0adc63d1eda2e0f7b61622 Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:57:40 +0000 Subject: [PATCH 204/860] Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Prettier check completed From 661b354277d71a9a5005930b6b900c4d24601965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veith=20M=2E=20B=C3=BCrgerhoff?= Date: Mon, 24 Jun 2024 14:17:19 +0200 Subject: [PATCH 205/860] Fixed validation for RepoUrlPicker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Veith M. Bürgerhoff --- .changeset/honest-pears-run.md | 7 ++++ .../src/actions/azure.examples.ts | 6 ++-- .../src/actions/azure.test.ts | 33 +++++++++++-------- .../src/actions/azure.ts | 9 +++-- plugins/scaffolder-node/src/actions/util.ts | 4 +++ .../fields/RepoUrlPicker/validation.ts | 9 ++++- 6 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 .changeset/honest-pears-run.md diff --git a/.changeset/honest-pears-run.md b/.changeset/honest-pears-run.md new file mode 100644 index 0000000000..acf9543997 --- /dev/null +++ b/.changeset/honest-pears-run.md @@ -0,0 +1,7 @@ +--- +'@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 after the usage was changed to 'repo'. diff --git a/plugins/scaffolder-backend-module-azure/src/actions/azure.examples.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.examples.ts index d1459d1820..22c2299b30 100644 --- a/plugins/scaffolder-backend-module-azure/src/actions/azure.examples.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/azure.examples.ts @@ -29,7 +29,7 @@ export const examples: TemplateExample[] = [ name: 'Publish to Azure', input: { repoUrl: - 'dev.azure.com?organization=organization&owner=project&repo=repo', + 'dev.azure.com?organization=organization&project=project&repo=repo', }, }, ], @@ -45,7 +45,7 @@ export const examples: TemplateExample[] = [ name: 'Publish to Azure', input: { repoUrl: - 'dev.azure.com?organization=organization&owner=project&repo=repo', + 'dev.azure.com?organization=organization&project=project&repo=repo', description: 'Initialize a git repository', }, }, @@ -63,7 +63,7 @@ export const examples: TemplateExample[] = [ name: 'Publish to Azure', input: { repoUrl: - 'dev.azure.com?organization=organization&owner=project&repo=repo', + 'dev.azure.com?organization=organization&project=project&repo=repo', defaultBranch: 'main', }, }, diff --git a/plugins/scaffolder-backend-module-azure/src/actions/azure.test.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.test.ts index a21520f751..140c77fb52 100644 --- a/plugins/scaffolder-backend-module-azure/src/actions/azure.test.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/azure.test.ts @@ -55,7 +55,9 @@ describe('publish:azure', () => { const action = createPublishAzureAction({ integrations, config }); const mockContext = createMockActionContext({ - input: { repoUrl: 'dev.azure.com?repo=repo&owner=owner&organization=org' }, + input: { + repoUrl: 'dev.azure.com?repo=repo&project=project&organization=org', + }, }); const mockGitClient = { @@ -77,19 +79,19 @@ describe('publish:azure', () => { ...mockContext, input: { repoUrl: 'dev.azure.com?repo=bob' }, }), - ).rejects.toThrow(/missing owner/); + ).rejects.toThrow(/missing project/); await expect( action.handler({ ...mockContext, - input: { repoUrl: 'dev.azure.com?owner=owner' }, + input: { repoUrl: 'dev.azure.com?project=project' }, }), ).rejects.toThrow(/missing repo/); await expect( action.handler({ ...mockContext, - input: { repoUrl: 'dev.azure.com?owner=owner&repo=repo' }, + input: { repoUrl: 'dev.azure.com?project=project&repo=repo' }, }), ).rejects.toThrow(/missing organization/); }); @@ -98,7 +100,9 @@ describe('publish:azure', () => { await expect( action.handler({ ...mockContext, - input: { repoUrl: 'azure.com?repo=bob&owner=owner&organization=org' }, + input: { + repoUrl: 'azure.com?repo=bob&project=project&organization=org', + }, }), ).rejects.toThrow(/No matching integration configuration/); }); @@ -109,7 +113,7 @@ describe('publish:azure', () => { ...mockContext, input: { repoUrl: - 'myazurehostnotoken.com?repo=bob&owner=owner&organization=org', + 'myazurehostnotoken.com?repo=bob&project=project&organization=org', }, }), ).rejects.toThrow( @@ -122,7 +126,7 @@ describe('publish:azure', () => { action.handler({ ...mockContext, input: { - repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org', + repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org', }, }), ).rejects.toThrow(/Unable to create the repository/); @@ -138,7 +142,8 @@ describe('publish:azure', () => { await action.handler({ ...mockContext, input: { - repoUrl: 'myazurehostnotoken.com?repo=bob&owner=owner&organization=org', + repoUrl: + 'myazurehostnotoken.com?repo=bob&project=project&organization=org', token: 'lols', }, }); @@ -152,7 +157,7 @@ describe('publish:azure', () => { { name: 'bob', }, - 'owner', + 'project', ); }); @@ -166,7 +171,7 @@ describe('publish:azure', () => { action.handler({ ...mockContext, input: { - repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org', + repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org', }, }), ).rejects.toThrow(/No remote URL returned/); @@ -182,7 +187,7 @@ describe('publish:azure', () => { action.handler({ ...mockContext, input: { - repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org', + repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org', }, }), ).rejects.toThrow(/No Id returned/); @@ -198,7 +203,7 @@ describe('publish:azure', () => { action.handler({ ...mockContext, input: { - repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org', + repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org', }, }), ).rejects.toThrow(/No web URL returned/); @@ -214,7 +219,7 @@ describe('publish:azure', () => { await action.handler({ ...mockContext, input: { - repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org', + repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org', }, }); @@ -227,7 +232,7 @@ describe('publish:azure', () => { { name: 'bob', }, - 'owner', + 'project', ); }); diff --git a/plugins/scaffolder-backend-module-azure/src/actions/azure.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.ts index bd75cedc65..a284f463a6 100644 --- a/plugins/scaffolder-backend-module-azure/src/actions/azure.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/azure.ts @@ -136,7 +136,7 @@ export function createPublishAzureAction(options: { gitAuthorEmail, } = ctx.input; - const { owner, repo, host, organization } = parseRepoUrl( + const { project, repo, host, organization } = parseRepoUrl( repoUrl, integrations, ); @@ -166,11 +166,14 @@ export function createPublishAzureAction(options: { const webApi = new WebApi(url, authHandler); const client = await webApi.getGitApi(); const createOptions: GitRepositoryCreateOptions = { name: repo }; - const returnedRepo = await client.createRepository(createOptions, owner); + const returnedRepo = await client.createRepository( + createOptions, + project, + ); if (!returnedRepo) { throw new InputError( - `Unable to create the repository with Organization ${organization}, Project ${owner} and Repo ${repo}. + `Unable to create the repository with Organization ${organization}, Project ${project} and Repo ${repo}. Please make sure that both the Org and Project are typed corrected and exist.`, ); } diff --git a/plugins/scaffolder-node/src/actions/util.ts b/plugins/scaffolder-node/src/actions/util.ts index 2b3a1296bf..5e4ce60a1a 100644 --- a/plugins/scaffolder-node/src/actions/util.ts +++ b/plugins/scaffolder-node/src/actions/util.ts @@ -85,6 +85,10 @@ export const parseRepoUrl = ( checkRequiredParams(parsed, 'project', 'repo'); break; } + case 'azure': { + checkRequiredParams(parsed, 'project', 'repo'); + break; + } case 'gitlab': { // project is the projectID, and if defined, owner and repo won't be needed. if (!project) { diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts index 55ba92abdc..c8dc66ab4c 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts @@ -54,7 +54,14 @@ export const repoPickerValidation = ( ); } } - // For anything other than bitbucket and gerrit + if (integrationApi?.byHost(host)?.type === 'azure') { + if (!searchParams.get('project')) { + validation.addError( + 'Incomplete repository location provided, project not provided', + ); + } + } + // For anything other than bitbucket, azure, and gerrit else if (integrationApi?.byHost(host)?.type !== 'gerrit') { if (!searchParams.get('owner')) { validation.addError( From 8c09c97c9f5c354661cf75d9a50dcca311cb0433 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 24 Jun 2024 14:10:51 +0200 Subject: [PATCH 206/860] refactor: deprecate status check handler Signed-off-by: Camila Belo --- .changeset/chilly-roses-trade.md | 5 +++++ packages/backend-common/api-report.md | 8 ++++---- .../src/deprecated/middleware/index.ts | 1 + .../middleware/statusCheckHandler.test.ts | 0 .../middleware/statusCheckHandler.ts | 3 +++ .../service/createStatusCheckRouter.test.ts | 0 .../service/createStatusCheckRouter.ts | 4 ++-- .../src/deprecated/service/index.ts | 1 + packages/backend-common/src/index.ts | 2 -- packages/backend-common/src/middleware/index.ts | 17 ----------------- packages/backend-common/src/service/index.ts | 17 ----------------- 11 files changed, 16 insertions(+), 42 deletions(-) create mode 100644 .changeset/chilly-roses-trade.md rename packages/backend-common/src/{ => deprecated}/middleware/statusCheckHandler.test.ts (100%) rename packages/backend-common/src/{ => deprecated}/middleware/statusCheckHandler.ts (73%) rename packages/backend-common/src/{ => deprecated}/service/createStatusCheckRouter.test.ts (100%) rename packages/backend-common/src/{ => deprecated}/service/createStatusCheckRouter.ts (85%) delete mode 100644 packages/backend-common/src/middleware/index.ts delete mode 100644 packages/backend-common/src/service/index.ts diff --git a/.changeset/chilly-roses-trade.md b/.changeset/chilly-roses-trade.md new file mode 100644 index 0000000000..73fc3ff766 --- /dev/null +++ b/.changeset/chilly-roses-trade.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Deprecate legacy status check factory, handler and types. diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index de00ef6a5a..52b661bcaf 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -184,7 +184,7 @@ export function createRootLogger( // @public @deprecated export function createServiceBuilder(_module: NodeModule): ServiceBuilder; -// @public +// @public @deprecated export function createStatusCheckRouter(options: { logger: LoggerService; path?: string; @@ -645,15 +645,15 @@ export type StaticAuthOptions = { logger?: LoggerService; }; -// @public +// @public @deprecated export type StatusCheck = () => Promise; -// @public +// @public @deprecated export function statusCheckHandler( options?: StatusCheckHandlerOptions, ): Promise; -// @public +// @public @deprecated export interface StatusCheckHandlerOptions { statusCheck?: StatusCheck; } diff --git a/packages/backend-common/src/deprecated/middleware/index.ts b/packages/backend-common/src/deprecated/middleware/index.ts index 6c284cc6ec..f4f4fcde0b 100644 --- a/packages/backend-common/src/deprecated/middleware/index.ts +++ b/packages/backend-common/src/deprecated/middleware/index.ts @@ -17,3 +17,4 @@ export * from './errorHandler'; export * from './notFoundHandler'; export * from './requestLoggingHandler'; +export * from './statusCheckHandler'; diff --git a/packages/backend-common/src/middleware/statusCheckHandler.test.ts b/packages/backend-common/src/deprecated/middleware/statusCheckHandler.test.ts similarity index 100% rename from packages/backend-common/src/middleware/statusCheckHandler.test.ts rename to packages/backend-common/src/deprecated/middleware/statusCheckHandler.test.ts diff --git a/packages/backend-common/src/middleware/statusCheckHandler.ts b/packages/backend-common/src/deprecated/middleware/statusCheckHandler.ts similarity index 73% rename from packages/backend-common/src/middleware/statusCheckHandler.ts rename to packages/backend-common/src/deprecated/middleware/statusCheckHandler.ts index 4bd1a701c3..ebaf84c1b9 100644 --- a/packages/backend-common/src/middleware/statusCheckHandler.ts +++ b/packages/backend-common/src/deprecated/middleware/statusCheckHandler.ts @@ -21,6 +21,7 @@ import { NextFunction, Request, Response, RequestHandler } from 'express'; * {@link createStatusCheckRouter}. * * @public + * @deprecated Migrate to the {@link https://backstage.io/docs/backend-system/ | new backend system} and use the {@link https://backstage.io/docs/backend-system/core-services/root-health | Root Health Service} instead. */ export type StatusCheck = () => Promise; @@ -28,6 +29,7 @@ export type StatusCheck = () => Promise; * Options passed to {@link statusCheckHandler}. * * @public + * @deprecated Migrate to the {@link https://backstage.io/docs/backend-system/ | new backend system} and use the {@link https://backstage.io/docs/backend-system/core-services/root-health | Root Health Service} instead. */ export interface StatusCheckHandlerOptions { /** @@ -44,6 +46,7 @@ export interface StatusCheckHandlerOptions { * @public * @param options - An optional configuration object. * @returns An Express error request handler + * @deprecated Migrate to the {@link https://backstage.io/docs/backend-system/ | new backend system} and use the {@link https://backstage.io/docs/backend-system/core-services/root-health | Root Health Service} instead. */ export async function statusCheckHandler( options: StatusCheckHandlerOptions = {}, diff --git a/packages/backend-common/src/service/createStatusCheckRouter.test.ts b/packages/backend-common/src/deprecated/service/createStatusCheckRouter.test.ts similarity index 100% rename from packages/backend-common/src/service/createStatusCheckRouter.test.ts rename to packages/backend-common/src/deprecated/service/createStatusCheckRouter.test.ts diff --git a/packages/backend-common/src/service/createStatusCheckRouter.ts b/packages/backend-common/src/deprecated/service/createStatusCheckRouter.ts similarity index 85% rename from packages/backend-common/src/service/createStatusCheckRouter.ts rename to packages/backend-common/src/deprecated/service/createStatusCheckRouter.ts index 1a5953a748..fdece10ec5 100644 --- a/packages/backend-common/src/service/createStatusCheckRouter.ts +++ b/packages/backend-common/src/deprecated/service/createStatusCheckRouter.ts @@ -17,8 +17,7 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import Router from 'express-promise-router'; import express from 'express'; -import { errorHandler } from '../deprecated'; -import { statusCheckHandler, StatusCheck } from '../middleware'; +import { errorHandler, statusCheckHandler, StatusCheck } from '..'; /** * Creates a default status checking router, that you can add to your express @@ -31,6 +30,7 @@ import { statusCheckHandler, StatusCheck } from '../middleware'; * requests. * * @public + * @deprecated Migrate to the {@link https://backstage.io/docs/backend-system/ | new backend system} and use the {@link https://backstage.io/docs/backend-system/core-services/root-health | Root Health Service} instead. */ export async function createStatusCheckRouter(options: { logger: LoggerService; diff --git a/packages/backend-common/src/deprecated/service/index.ts b/packages/backend-common/src/deprecated/service/index.ts index a9fc43c22a..d01f25fad3 100644 --- a/packages/backend-common/src/deprecated/service/index.ts +++ b/packages/backend-common/src/deprecated/service/index.ts @@ -15,4 +15,5 @@ */ export { createServiceBuilder } from './createServiceBuilder'; +export { createStatusCheckRouter } from './createStatusCheckRouter'; export type { ServiceBuilder, RequestLoggingHandlerFactory } from './types'; diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index cb5e236888..ad5621b5a9 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -22,5 +22,3 @@ export * from './deprecated'; export * from './compat'; -export * from './middleware'; -export * from './service'; diff --git a/packages/backend-common/src/middleware/index.ts b/packages/backend-common/src/middleware/index.ts deleted file mode 100644 index f1754ef4d8..0000000000 --- a/packages/backend-common/src/middleware/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export * from './statusCheckHandler'; diff --git a/packages/backend-common/src/service/index.ts b/packages/backend-common/src/service/index.ts deleted file mode 100644 index c2ae6ba87b..0000000000 --- a/packages/backend-common/src/service/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { createStatusCheckRouter } from './createStatusCheckRouter'; From ec2fd03122902961bf0c7e7fd02e357d04d62e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veith=20M=2E=20B=C3=BCrgerhoff?= Date: Mon, 24 Jun 2024 14:26:02 +0200 Subject: [PATCH 207/860] Use else-if instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Veith M. Bürgerhoff --- .../src/components/fields/RepoUrlPicker/validation.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts index c8dc66ab4c..06c2fd5684 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts @@ -53,8 +53,7 @@ export const repoPickerValidation = ( 'Incomplete repository location provided, project not provided', ); } - } - if (integrationApi?.byHost(host)?.type === 'azure') { + } else if (integrationApi?.byHost(host)?.type === 'azure') { if (!searchParams.get('project')) { validation.addError( 'Incomplete repository location provided, project not provided', From f229d94b8abd8a79f651266705740e7b8ec8cd17 Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Mon, 24 Jun 2024 13:29:53 +0100 Subject: [PATCH 208/860] 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 11eaadec04ca0cb0b3cc7e4e5ec17089b6f9cd42 Mon Sep 17 00:00:00 2001 From: Mattias Folke Date: Mon, 24 Jun 2024 14:38:33 +0200 Subject: [PATCH 209/860] clarified User Photos for userGroupmember for Azure integration Signed-off-by: Mattias Folke --- docs/integrations/azure/org.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 89abd4813b..c3b0dc264f 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -150,6 +150,18 @@ microsoftGraphOrg: loadPhotos: false ``` +If you are using `userGroupMember`, the configuration for `loadPhotos` should still be managed under `users:` while omitting `search` and `filters`. + +```yaml +microsoftGraphOrg: + providerId: + user: + loadPhotos: false + userGroupMember: + filter: "displayName eq 'Backstage Users'" + search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' +``` + ## Customizing Transformation Ingested entities can be customized by providing custom transformers. From d1488caaa309df834095bde5a48bf9f99ad797af Mon Sep 17 00:00:00 2001 From: Stephen Date: Mon, 24 Jun 2024 08:52:29 -0400 Subject: [PATCH 210/860] 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 574a2b2feed9d33c70d80a497994ef7a26e171ac Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:18:22 +0000 Subject: [PATCH 211/860] Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Added some tags --- microsite/data/plugins/harness-chaos.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/microsite/data/plugins/harness-chaos.yaml b/microsite/data/plugins/harness-chaos.yaml index 563f29d6a1..19b91046f6 100644 --- a/microsite/data/plugins/harness-chaos.yaml +++ b/microsite/data/plugins/harness-chaos.yaml @@ -7,7 +7,6 @@ documentation: https://github.com/harness/backstage-plugins/tree/main/plugins/ha iconUrl: https://static.harness.io/ng-static/images/favicon.png npmPackageName: '@harnessio/backstage-plugin-harness-chaos' tags: - - chaos-experiments + - chaosexperiments - resiliency - - chaos-engineering addedDate: '2024-06-25' \ No newline at end of file From 148a6f17b466c7a26468faa6695ff521594a6c31 Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Mon, 24 Jun 2024 15:28:56 +0200 Subject: [PATCH 212/860] Update silent-moose-eat.md Signed-off-by: Ben Lambert --- .changeset/silent-moose-eat.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/silent-moose-eat.md b/.changeset/silent-moose-eat.md index 735afa12f1..bc66f55181 100644 --- a/.changeset/silent-moose-eat.md +++ b/.changeset/silent-moose-eat.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder': patch --- -Support catalogFilter array on OwnedEntityPicker +Support `catalogFilter` array on `OwnedEntityPicker` From 589860ec27f7fbe2cb96e5266737850a6c2c5ead Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 15:26:53 +0200 Subject: [PATCH 213/860] 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 214/860] 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 215/860] 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 995b2c56da7bf4f2e58e4b64f3ae29249a3e9e95 Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:34:39 +0000 Subject: [PATCH 216/860] Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Ran prettier --- microsite/data/plugins/harness-chaos.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/microsite/data/plugins/harness-chaos.yaml b/microsite/data/plugins/harness-chaos.yaml index 19b91046f6..ade6f9e566 100644 --- a/microsite/data/plugins/harness-chaos.yaml +++ b/microsite/data/plugins/harness-chaos.yaml @@ -7,6 +7,5 @@ documentation: https://github.com/harness/backstage-plugins/tree/main/plugins/ha iconUrl: https://static.harness.io/ng-static/images/favicon.png npmPackageName: '@harnessio/backstage-plugin-harness-chaos' tags: - - chaosexperiments - resiliency -addedDate: '2024-06-25' \ No newline at end of file +addedDate: '2024-06-25' From d3c39fc71c7dfac02e70f2c16f006dad595e3ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 24 Jun 2024 15:46:20 +0200 Subject: [PATCH 217/860] declaratively disable external routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/famous-dodos-crash.md | 15 +++++++ .../src/app/resolveRouteBindings.test.ts | 31 +++++++++++++ .../src/app/resolveRouteBindings.ts | 43 +++++++++++++------ .../src/routing/resolveRouteBindings.test.ts | 27 ++++++++++++ .../src/routing/resolveRouteBindings.ts | 43 +++++++++++++------ 5 files changed, 133 insertions(+), 26 deletions(-) create mode 100644 .changeset/famous-dodos-crash.md diff --git a/.changeset/famous-dodos-crash.md b/.changeset/famous-dodos-crash.md new file mode 100644 index 0000000000..5442c1b378 --- /dev/null +++ b/.changeset/famous-dodos-crash.md @@ -0,0 +1,15 @@ +--- +'@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/packages/core-app-api/src/app/resolveRouteBindings.test.ts b/packages/core-app-api/src/app/resolveRouteBindings.test.ts index 9dfbbfd452..7d5c649a34 100644 --- a/packages/core-app-api/src/app/resolveRouteBindings.test.ts +++ b/packages/core-app-api/src/app/resolveRouteBindings.test.ts @@ -194,4 +194,35 @@ describe('collectRouteIds', () => { 'test.extRef': extRef, }); }); + + it('can disable external routes that have defaults', () => { + const source = createExternalRouteRef({ + id: 'test', + defaultTarget: 'test.target1', + }); + const target1 = createRouteRef({ id: 'test' }); + const plugin = createPlugin({ + id: 'test', + routes: { target1 }, + externalRoutes: { source }, + }); + + // resolves normally with no config + let result = resolveRouteBindings(() => {}, new MockConfigApi({}), [ + plugin, + ]); + + expect(result.get(source)).toBe(target1); + + // can be disabled + result = resolveRouteBindings( + () => {}, + new MockConfigApi({ + app: { routes: { bindings: { 'test.source': false } } }, + }), + [plugin], + ); + + expect(result.get(source)).toBe(undefined); + }); }); diff --git a/packages/core-app-api/src/app/resolveRouteBindings.ts b/packages/core-app-api/src/app/resolveRouteBindings.ts index 55e1139b29..07dfea43ee 100644 --- a/packages/core-app-api/src/app/resolveRouteBindings.ts +++ b/packages/core-app-api/src/app/resolveRouteBindings.ts @@ -102,11 +102,12 @@ export function resolveRouteBindings( const bindings = config .getOptionalConfig('app.routes.bindings') ?.get(); + const disabledExternalRefs = new Set(); if (bindings) { for (const [externalRefId, targetRefId] of Object.entries(bindings)) { - if (typeof targetRefId !== 'string' || targetRefId === '') { + if (!isValidTargetRefId(targetRefId)) { throw new Error( - `Invalid config at app.routes.bindings['${externalRefId}'], value must be a non-empty string`, + `Invalid config at app.routes.bindings['${externalRefId}'], value must be a non-empty string or false`, ); } @@ -116,23 +117,27 @@ export function resolveRouteBindings( `Invalid config at app.routes.bindings, '${externalRefId}' is not a valid external route`, ); } - if (result.has(externalRef)) { - continue; - } - const targetRef = routesById.routes.get(targetRefId); - if (!targetRef) { - throw new Error( - `Invalid config at app.routes.bindings['${externalRefId}'], '${targetRefId}' is not a valid route`, - ); - } - result.set(externalRef, targetRef); + if (targetRefId === false) { + disabledExternalRefs.add(externalRef); + + result.delete(externalRef); + } else if (!result.has(externalRef)) { + const targetRef = routesById.routes.get(targetRefId); + if (!targetRef) { + throw new Error( + `Invalid config at app.routes.bindings['${externalRefId}'], '${targetRefId}' is not a valid route`, + ); + } + + result.set(externalRef, targetRef); + } } } // Finally fall back to attempting to map defaults, at lowest priority for (const externalRef of routesById.externalRoutes.values()) { - if (!result.has(externalRef)) { + if (!result.has(externalRef) && !disabledExternalRefs.has(externalRef)) { const defaultRefId = 'getDefaultTarget' in externalRef ? (externalRef.getDefaultTarget as () => string | undefined)() @@ -148,3 +153,15 @@ export function resolveRouteBindings( return result; } + +function isValidTargetRefId(value: unknown): value is string | false { + if (value === false) { + return true; + } + + if (typeof value === 'string' && value) { + return true; + } + + return false; +} diff --git a/packages/frontend-app-api/src/routing/resolveRouteBindings.test.ts b/packages/frontend-app-api/src/routing/resolveRouteBindings.test.ts index 9b150eb127..908a99d3aa 100644 --- a/packages/frontend-app-api/src/routing/resolveRouteBindings.test.ts +++ b/packages/frontend-app-api/src/routing/resolveRouteBindings.test.ts @@ -161,4 +161,31 @@ describe('resolveRouteBindings', () => { expect(result.get(source)).toBe(target2); }); + + it('can disable external routes that have defaults', () => { + const source = createExternalRouteRef({ defaultTarget: 'target1' }); + const target1 = createRouteRef(); + const routesById = { + routes: new Map([['target1', target1]]), + externalRoutes: new Map([['source', source]]), + }; + + // resolves normally with no config + let result = resolveRouteBindings( + () => {}, + new ConfigReader({}), + routesById, + ); + + expect(result.get(source)).toBe(target1); + + // can be disabled + result = resolveRouteBindings( + () => {}, + new ConfigReader({ app: { routes: { bindings: { source: false } } } }), + routesById, + ); + + expect(result.get(source)).toBe(undefined); + }); }); diff --git a/packages/frontend-app-api/src/routing/resolveRouteBindings.ts b/packages/frontend-app-api/src/routing/resolveRouteBindings.ts index 49e3b1a1be..81d9eddef3 100644 --- a/packages/frontend-app-api/src/routing/resolveRouteBindings.ts +++ b/packages/frontend-app-api/src/routing/resolveRouteBindings.ts @@ -112,11 +112,12 @@ export function resolveRouteBindings( const bindings = config .getOptionalConfig('app.routes.bindings') ?.get(); + const disabledExternalRefs = new Set(); if (bindings) { for (const [externalRefId, targetRefId] of Object.entries(bindings)) { - if (typeof targetRefId !== 'string' || targetRefId === '') { + if (!isValidTargetRefId(targetRefId)) { throw new Error( - `Invalid config at app.routes.bindings['${externalRefId}'], value must be a non-empty string`, + `Invalid config at app.routes.bindings['${externalRefId}'], value must be a non-empty string or false`, ); } @@ -126,23 +127,27 @@ export function resolveRouteBindings( `Invalid config at app.routes.bindings, '${externalRefId}' is not a valid external route`, ); } - if (result.has(externalRef)) { - continue; - } - const targetRef = routesById.routes.get(targetRefId); - if (!targetRef) { - throw new Error( - `Invalid config at app.routes.bindings['${externalRefId}'], '${targetRefId}' is not a valid route`, - ); - } - result.set(externalRef, targetRef); + if (targetRefId === false) { + disabledExternalRefs.add(externalRef); + + result.delete(externalRef); + } else if (!result.has(externalRef)) { + const targetRef = routesById.routes.get(targetRefId); + if (!targetRef) { + throw new Error( + `Invalid config at app.routes.bindings['${externalRefId}'], '${targetRefId}' is not a valid route`, + ); + } + + result.set(externalRef, targetRef); + } } } // Finally fall back to attempting to map defaults, at lowest priority for (const externalRef of routesById.externalRoutes.values()) { - if (!result.has(externalRef)) { + if (!result.has(externalRef) && !disabledExternalRefs.has(externalRef)) { const defaultRefId = toInternalExternalRouteRef(externalRef).getDefaultTarget(); if (defaultRefId) { @@ -156,3 +161,15 @@ export function resolveRouteBindings( return result; } + +function isValidTargetRefId(value: unknown): value is string | false { + if (value === false) { + return true; + } + + if (typeof value === 'string' && value) { + return true; + } + + return false; +} From 7a5da335ae30c2b15ed44279e40735afccafbb62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veith=20M=2E=20B=C3=BCrgerhoff?= Date: Mon, 24 Jun 2024 15:51:58 +0200 Subject: [PATCH 218/860] Add tests for azure validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Veith M. Bürgerhoff --- .../fields/RepoUrlPicker/validation.test.ts | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts index b9c481957c..2b59775d3a 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts @@ -36,6 +36,11 @@ describe('RepoPicker Validation', () => { host: 'server.bitbucket.com', }, ], + azure: [ + { + host: 'dev.azure.com', + }, + ], github: [ { host: 'github.com', @@ -201,4 +206,59 @@ describe('RepoPicker Validation', () => { 'Incomplete repository location provided, repo not provided', ); }); + + it('validates properly with proper input for azure', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation( + 'dev.azure.com?project=a&repo=b', + mockFieldValidation, + { + apiHolder: apiHolderMock, + }, + ); + + expect(mockFieldValidation.addError).not.toHaveBeenCalled(); + }); + + it('validates when no project or repo provided for azure', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation('dev.azure.com', mockFieldValidation, { + apiHolder: apiHolderMock, + }); + + expect(mockFieldValidation.addError).toHaveBeenNthCalledWith( + 1, + 'Incomplete repository location provided, project not provided', + ); + expect(mockFieldValidation.addError).toHaveBeenNthCalledWith( + 2, + 'Incomplete repository location provided, repo not provided', + ); + }); + + it('validates when no project provided for azure', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation('dev.azure.com?repo=r', mockFieldValidation, { + apiHolder: apiHolderMock, + }); + + expect(mockFieldValidation.addError).toHaveBeenCalledWith( + 'Incomplete repository location provided, project not provided', + ); + }); + + it('validates when no repo provided for azure', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation('dev.azure.com?project=p', mockFieldValidation, { + apiHolder: apiHolderMock, + }); + + expect(mockFieldValidation.addError).toHaveBeenCalledWith( + 'Incomplete repository location provided, repo not provided', + ); + }); }); From a03b86497b59124967dc4812ccec7de261c74658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 24 Jun 2024 15:54:14 +0200 Subject: [PATCH 219/860] review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- packages/frontend-app-api/config.d.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/frontend-app-api/config.d.ts b/packages/frontend-app-api/config.d.ts index 28355f5376..fc265e8833 100644 --- a/packages/frontend-app-api/config.d.ts +++ b/packages/frontend-app-api/config.d.ts @@ -26,9 +26,14 @@ 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 }; + bindings?: { [externalRouteRefId: string]: string | false }; }; /** From 9986ab0a977672498a92829766a5442d1718cda3 Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Mon, 24 Jun 2024 16:18:56 +0200 Subject: [PATCH 220/860] Update honest-pears-run.md Signed-off-by: Ben Lambert --- .changeset/honest-pears-run.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/honest-pears-run.md b/.changeset/honest-pears-run.md index acf9543997..65ea8d1721 100644 --- a/.changeset/honest-pears-run.md +++ b/.changeset/honest-pears-run.md @@ -4,4 +4,4 @@ '@backstage/plugin-scaffolder': patch --- -Fixed a bug where the RepoUrlPicker would still require the 'owner' field after the usage was changed to 'repo'. +Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` From f6581944cc17da9780c01d36c2c3166212bc67bd Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 17:23:28 +0200 Subject: [PATCH 221/860] 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 222/860] 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 223/860] 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 224/860] 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 225/860] 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 226/860] 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 52b6db0922c6d5d636076fe9793e39a8eff79cf9 Mon Sep 17 00:00:00 2001 From: Mikko Korhonen Date: Mon, 24 Jun 2024 21:57:33 +0300 Subject: [PATCH 227/860] feat(scaffolder): use virtualization with EntityPicker Signed-off-by: Mikko Korhonen --- .changeset/calm-jeans-ring.md | 5 ++ .../fields/EntityPicker/EntityPicker.tsx | 2 + .../MultiEntityPicker/MultiEntityPicker.tsx | 36 +------------ .../components/fields/VirtualizedListbox.tsx | 50 +++++++++++++++++++ 4 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 .changeset/calm-jeans-ring.md create mode 100644 plugins/scaffolder/src/components/fields/VirtualizedListbox.tsx diff --git a/.changeset/calm-jeans-ring.md b/.changeset/calm-jeans-ring.md new file mode 100644 index 0000000000..3d1efcf7bd --- /dev/null +++ b/.changeset/calm-jeans-ring.md @@ -0,0 +1,5 @@ +--- +'@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/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx index 176f6e9ce0..9eca3e85c5 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx @@ -43,6 +43,7 @@ import { EntityPickerUiOptions, EntityPickerFilterQuery, } from './schema'; +import { VirtualizedListbox } from '../VirtualizedListbox'; export { EntityPickerSchema } from './schema'; @@ -205,6 +206,7 @@ export const EntityPicker = (props: EntityPickerProps) => { entities?.entityRefToPresentation.get(stringifyEntityRef(option)) ?.primaryTitle!, })} + ListboxComponent={VirtualizedListbox} /> ); diff --git a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx index 84a050622a..d800c9b372 100644 --- a/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx @@ -35,7 +35,6 @@ import Autocomplete, { AutocompleteChangeReason, } from '@material-ui/lab/Autocomplete'; import React, { useCallback, useEffect } from 'react'; -import { FixedSizeList, ListChildComponentProps } from 'react-window'; import useAsync from 'react-use/esm/useAsync'; import { FieldValidation } from '@rjsf/utils'; import { @@ -44,41 +43,10 @@ import { MultiEntityPickerUiOptions, MultiEntityPickerFilterQuery, } from './schema'; +import { VirtualizedListbox } from '../VirtualizedListbox'; export { MultiEntityPickerSchema } from './schema'; -const renderRow = (props: ListChildComponentProps) => { - const { data, index, style } = props; - return React.cloneElement(data[index], { style }); -}; - -const ListboxComponent = React.forwardRef< - HTMLDivElement, - { children?: React.ReactNode } ->((props, ref) => { - const itemData = React.Children.toArray(props.children); - const itemCount = itemData.length; - - const itemSize = 36; - - const itemsToShow = Math.min(10, itemCount); - const height = Math.max(itemSize, itemsToShow * itemSize - 0.5 * itemSize); - - return ( -
    - - {renderRow} - -
    - ); -}); - /** * The underlying component that is rendered in the form for the `MultiEntityPicker` * field extension. @@ -210,7 +178,7 @@ export const MultiEntityPicker = (props: MultiEntityPickerProps) => { }} /> )} - ListboxComponent={ListboxComponent} + ListboxComponent={VirtualizedListbox} /> ); diff --git a/plugins/scaffolder/src/components/fields/VirtualizedListbox.tsx b/plugins/scaffolder/src/components/fields/VirtualizedListbox.tsx new file mode 100644 index 0000000000..b0920b626a --- /dev/null +++ b/plugins/scaffolder/src/components/fields/VirtualizedListbox.tsx @@ -0,0 +1,50 @@ +/* + * 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 { FixedSizeList, ListChildComponentProps } from 'react-window'; + +const renderRow = (props: ListChildComponentProps) => { + const { data, index, style } = props; + return React.cloneElement(data[index], { style }); +}; + +export const VirtualizedListbox = React.forwardRef< + HTMLDivElement, + { children?: React.ReactNode } +>((props, ref) => { + const itemData = React.Children.toArray(props.children); + const itemCount = itemData.length; + + const itemSize = 36; + + const itemsToShow = Math.min(10, itemCount); + const height = Math.max(itemSize, itemsToShow * itemSize - 0.5 * itemSize); + + return ( +
    + + {renderRow} + +
    + ); +}); 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 228/860] 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 229/860] 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 230/860] 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 231/860] 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 232/860] 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 4410fed9d9f10fefc7520bab5d702dd7c3c36913 Mon Sep 17 00:00:00 2001 From: Diego Iglesias Date: Mon, 24 Jun 2024 23:40:01 +0200 Subject: [PATCH 233/860] fix(scaffolder-backend-module-github): createEnvironmentVariable missing owner and repo Signed-off-by: Diego Iglesias --- .changeset/ten-dancers-drum.md | 5 +++++ .../src/actions/githubEnvironment.examples.test.ts | 4 ++++ .../src/actions/githubEnvironment.test.ts | 4 ++++ .../src/actions/githubEnvironment.ts | 2 ++ 4 files changed, 15 insertions(+) create mode 100644 .changeset/ten-dancers-drum.md diff --git a/.changeset/ten-dancers-drum.md b/.changeset/ten-dancers-drum.md new file mode 100644 index 0000000000..427c507c8c --- /dev/null +++ b/.changeset/ten-dancers-drum.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Fixed issue with octokit call missing owner and repo when creating environment variables using github:environment:create action diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts index 9d4395eb7a..0a9242627c 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts @@ -221,6 +221,8 @@ describe('github:environment:create examples', () => { mockOctokit.rest.actions.createEnvironmentVariable, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', name: 'key1', value: 'val1', @@ -229,6 +231,8 @@ describe('github:environment:create examples', () => { mockOctokit.rest.actions.createEnvironmentVariable, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', name: 'key2', value: 'val2', 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 a8d8c4ef2e..b0fa08dae4 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts @@ -240,6 +240,8 @@ describe('github:environment:create', () => { mockOctokit.rest.actions.createEnvironmentVariable, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', name: 'key1', value: 'val1', @@ -248,6 +250,8 @@ describe('github:environment:create', () => { mockOctokit.rest.actions.createEnvironmentVariable, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', name: 'key2', value: 'val2', diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts index e821ff0cd6..f6542e3d83 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts @@ -187,6 +187,8 @@ export function createGithubEnvironmentAction(options: { for (const [key, value] of Object.entries(environmentVariables ?? {})) { await client.rest.actions.createEnvironmentVariable({ repository_id: repository.data.id, + owner: owner, + repo: repo, environment_name: name, name: key, value, From 36f3c5e69330e33eb5d0035e86c0817c0557a861 Mon Sep 17 00:00:00 2001 From: Diego Iglesias Date: Tue, 25 Jun 2024 00:24:58 +0200 Subject: [PATCH 234/860] fix(scaffolder-backend-module-github): createOrUpdateEnvironmentSecret missing owner and repo Signed-off-by: Diego Iglesias --- .changeset/ten-dancers-drum.md | 2 +- .../src/actions/githubEnvironment.examples.test.ts | 4 ++++ .../src/actions/githubEnvironment.test.ts | 4 ++++ .../src/actions/githubEnvironment.ts | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.changeset/ten-dancers-drum.md b/.changeset/ten-dancers-drum.md index 427c507c8c..3f54a7a6b3 100644 --- a/.changeset/ten-dancers-drum.md +++ b/.changeset/ten-dancers-drum.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend-module-github': patch --- -Fixed issue with octokit call missing owner and repo when creating environment variables using github:environment:create action +Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts index 0a9242627c..e41e642ca0 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts @@ -245,6 +245,8 @@ describe('github:environment:create examples', () => { mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', secret_name: 'secret1', key_id: 'keyid', @@ -254,6 +256,8 @@ describe('github:environment:create examples', () => { mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', secret_name: 'secret2', key_id: 'keyid', 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 b0fa08dae4..c4eae41029 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts @@ -286,6 +286,8 @@ describe('github:environment:create', () => { mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', secret_name: 'key1', key_id: 'keyid', @@ -295,6 +297,8 @@ describe('github:environment:create', () => { mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, ).toHaveBeenCalledWith({ repository_id: 'repoid', + owner: 'owner', + repo: 'repository', environment_name: 'envname', secret_name: 'key2', key_id: 'keyid', diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts index f6542e3d83..98e7cea1a9 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts @@ -220,6 +220,8 @@ export function createGithubEnvironmentAction(options: { await client.rest.actions.createOrUpdateEnvironmentSecret({ repository_id: repository.data.id, + owner: owner, + repo: repo, environment_name: name, secret_name: key, encrypted_value: encryptedBase64Secret, From d22886250c9ffe16e886f9caa3d467237e74f7bd Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Mon, 24 Jun 2024 23:07:46 -0400 Subject: [PATCH 235/860] Update cli default backend plugin to use non-deprecated imports Signed-off-by: Stephen Glass --- .changeset/khaki-rivers-obey.md | 6 ++++++ .../src/deprecated/middleware/errorHandler.ts | 2 +- .../templates/default-backend-plugin/package.json.hbs | 1 + .../templates/default-backend-plugin/src/plugin.ts.hbs | 3 +++ .../default-backend-plugin/src/service/router.test.ts | 5 +++-- .../default-backend-plugin/src/service/router.ts | 10 +++++++--- 6 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 .changeset/khaki-rivers-obey.md diff --git a/.changeset/khaki-rivers-obey.md b/.changeset/khaki-rivers-obey.md new file mode 100644 index 0000000000..856c8caf09 --- /dev/null +++ b/.changeset/khaki-rivers-obey.md @@ -0,0 +1,6 @@ +--- +'@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/packages/backend-common/src/deprecated/middleware/errorHandler.ts b/packages/backend-common/src/deprecated/middleware/errorHandler.ts index 3664ed0e0a..b4f07b9320 100644 --- a/packages/backend-common/src/deprecated/middleware/errorHandler.ts +++ b/packages/backend-common/src/deprecated/middleware/errorHandler.ts @@ -63,7 +63,7 @@ export type ErrorHandlerOptions = { * * @public * @returns An Express error request handler - * @deprecated Use {@link @backstage/backend-app-api#MiddlewareFactory.create.error} instead + * @deprecated Use {@link @backstage/backend-defaults/rootHttpRouter#MiddlewareFactory.create.error} instead */ export function errorHandler( options: ErrorHandlerOptions = {}, diff --git a/packages/cli/templates/default-backend-plugin/package.json.hbs b/packages/cli/templates/default-backend-plugin/package.json.hbs index c20a1854a2..57539d5e29 100644 --- a/packages/cli/templates/default-backend-plugin/package.json.hbs +++ b/packages/cli/templates/default-backend-plugin/package.json.hbs @@ -38,6 +38,7 @@ "node-fetch": "{{versionQuery 'node-fetch' '2.6.7'}}" }, "devDependencies": { + "@backstage/backend-test-utils": "{{versionQuery '@backstage/backend-test-utils'}}", "@backstage/cli": "{{versionQuery '@backstage/cli'}}", "@backstage/plugin-auth-backend": "{{versionQuery '@backstage/plugin-auth-backend'}}", "@backstage/plugin-auth-backend-module-guest-provider": "{{versionQuery '@backstage/plugin-auth-backend-module-guest-provider'}}", diff --git a/packages/cli/templates/default-backend-plugin/src/plugin.ts.hbs b/packages/cli/templates/default-backend-plugin/src/plugin.ts.hbs index 773bd4354f..bf04b43afe 100644 --- a/packages/cli/templates/default-backend-plugin/src/plugin.ts.hbs +++ b/packages/cli/templates/default-backend-plugin/src/plugin.ts.hbs @@ -16,14 +16,17 @@ export const {{pluginVar}} = createBackendPlugin({ deps: { httpRouter: coreServices.httpRouter, logger: coreServices.logger, + config: coreServices.rootConfig, }, async init({ httpRouter, logger, + config, }) { httpRouter.use( await createRouter({ logger, + config, }), ); httpRouter.addAuthPolicy({ diff --git a/packages/cli/templates/default-backend-plugin/src/service/router.test.ts b/packages/cli/templates/default-backend-plugin/src/service/router.test.ts index 4f5079744e..ed19d50d2b 100644 --- a/packages/cli/templates/default-backend-plugin/src/service/router.test.ts +++ b/packages/cli/templates/default-backend-plugin/src/service/router.test.ts @@ -1,4 +1,4 @@ -import { getVoidLogger } from '@backstage/backend-common'; +import { mockServices } from '@backstage/backend-test-utils'; import express from 'express'; import request from 'supertest'; @@ -9,7 +9,8 @@ describe('createRouter', () => { beforeAll(async () => { const router = await createRouter({ - logger: getVoidLogger(), + logger: mockServices.logger.mock(), + config: mockServices.rootConfig(), }); app = express().use(router); }); 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 ff7134e59d..312d7e252e 100644 --- a/packages/cli/templates/default-backend-plugin/src/service/router.ts +++ b/packages/cli/templates/default-backend-plugin/src/service/router.ts @@ -1,16 +1,18 @@ -import { errorHandler } from '@backstage/backend-common'; +import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; import express from 'express'; import Router from 'express-promise-router'; export interface RouterOptions { logger: LoggerService; + config: Config; } export async function createRouter( options: RouterOptions, ): Promise { - const { logger } = options; + const { logger, config } = options; const router = Router(); router.use(express.json()); @@ -20,6 +22,8 @@ export async function createRouter( response.json({ status: 'ok' }); }); - router.use(errorHandler()); + const middleware = MiddlewareFactory.create({ logger, config }); + + router.use(middleware.error()); return router; } From 70df2be217b7c26e23d5d7221d39182c145ee8de Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Tue, 25 Jun 2024 08:24:29 +0200 Subject: [PATCH 236/860] 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 c35be1d21b33a72c3698e980e97d3526fb35c66b Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 25 Jun 2024 09:28:28 +0200 Subject: [PATCH 237/860] e2e-tests: wait for plugins before start Signed-off-by: Vincenzo Scamporlino --- packages/e2e-test/src/commands/run.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/e2e-test/src/commands/run.ts b/packages/e2e-test/src/commands/run.ts index 111c638146..0a9ac6368c 100644 --- a/packages/e2e-test/src/commands/run.ts +++ b/packages/e2e-test/src/commands/run.ts @@ -537,7 +537,9 @@ async function testBackendStart(appDir: string, ...args: string[]) { try { await waitFor( - () => stdout.includes('Listening on ') || filterStderr(stderr).length > 0, + () => + stdout.includes('Plugin initialization complete') || + filterStderr(stderr).length > 0, ); const stderrLines = filterStderr(stderr); if (stderrLines.length > 0) { From d14795bd0587a52b87284628d8364ddf570d09f9 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 25 Jun 2024 10:31:38 +0200 Subject: [PATCH 238/860] chore: fixing tests Signed-off-by: blam --- .../fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index 18ce8d2c76..2ae89233ff 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -27,11 +27,9 @@ import { act } from 'react-dom/test-utils'; describe('BitbucketRepoPicker', () => { const scaffolderApiMock: Partial = { - autocomplete: jest - .fn() - .mockImplementation((_token, _provider, resource) => [ - `${resource}_example`, - ]), + autocomplete: jest.fn().mockImplementation(opts => ({ + results: [{ title: `${opts.resource}_example` }], + })), }; it('renders a select if there is a list of allowed owners', async () => { From 54a0cc779b39f12aecb1c4e9439e18f2007ae83a Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Mon, 24 Jun 2024 18:09:57 +0100 Subject: [PATCH 239/860] Creating dry run documentation Signed-off-by: Tavi Nolan --- docs/plugins/dry-run-testing.md | 135 ++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 136 insertions(+) create mode 100644 docs/plugins/dry-run-testing.md diff --git a/docs/plugins/dry-run-testing.md b/docs/plugins/dry-run-testing.md new file mode 100644 index 0000000000..18b7343920 --- /dev/null +++ b/docs/plugins/dry-run-testing.md @@ -0,0 +1,135 @@ +--- +id: dry run testing +title: Dry Run Testing +description: Documentation on how to enable and implement dry run testing in actions +--- + +Scaffolder templates can be tested using the dry run feature of scaffolder actions. This allows you to simulate the effects of running a scaffolder action without making any actual changes to your environment, for example creating a webhook in Github. Once dry run is enabled in the scaffolder action, you can add handling to actions you use in your scaffolder templates to define how an action should operate in a dry run scenario. + +## Enabling dry run testing + +To enable dry run for your scaffolder action you need to add 'supportsDryRun: true' to the configuration object of 'createTemplateAction' in the function where the behavior of your action is defined: + +```typescript +export function exampleAction() { + return createTemplateAction<{ + example: string; + }>({ + id: 'action:example', + description: 'Example action', + schema: { + input: { + type: 'object', + properties: { + example: { + title: 'example', + type: 'string', + }, + }, + }, + }, + supportsDryRun: true, + async handler(ctx) { + ... + }, + }); +} +``` + +## Adding handling for dry run + +To add handling for dry run functionality you need to add a check for 'ctx.isDryRun' inside the handler of the configuration object which is being passed into 'createTemplateAction' in the function where the behavior of your action is defined. Once the check is successful, you can perform the desired actions expected in a dry run, e.g. outputting non-sensitive inputs. + +```typescript +async handler(ctx) { + ... + + // If this is a dry run, log and return + if (ctx.isDryRun) { + ctx.logger.info(`Dry run complete`); + return; + } + + ... + }, +``` + +## Testing dry run handling + +You will also need to add tests for the dry run handling, for example: + +```typescript + it('should not perform action during dry run', async () => { + ... + + // Create the context object with the necessary properties for a dry run + const ctx = { + ...mockContext, + isDryRun: true, + input: { + ... + }, + }; + + // Call the handler with the context + await action.handler(ctx); + + expect(...); + }); +``` + +## Dry run via API call + +Dry run can be performed using the dry-run API, which allows the dry run to be completed in code. +This [command line script](https://github.com/backstage/backstage/blob/master/contrib/scaffolder/template-testing-dry-run.md) offers a way for you to do work with dry-run API. You run it against a running instance, either locally or remote, and use it like: + +```bash +scaffolder-dry http://localhost:7007/ template-directory values.yml output-directory +``` + +If you're using backend permissions, pass a front-end auth token from a current browser session via --token $FRONTEND_TOKEN. + +You can also query the dry run endpoint directly in code, for example: + +`dry-run.js` + +```javascript +const template = yaml.load( + await fs.readFile('path/to/templates/template.yaml', 'utf-8'), +); +const values = JSON.parse( + await fs.readFile('path/to/templates/template_values.json', 'utf-8'), +); + +// Prepare the request body +const body = { + template, + values, + directoryContents, +}; + +// Send the request to the dry-run endpoint +const response = await fetch( + 'http://localhost:7000/api/scaffolder/v2/dry-run', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ', // replace 'YOUR_API_KEY' with your actual API key + }, + body: JSON.stringify(body), + }, +); +``` + +`template_values.json` + +```json +{ + "example": "test", + "name": "helloworld" +} +``` + +In this example `template.yaml` is your template yaml file, `template_values.json` would be a json file containing key value pairs for your template inputs, and `directoryContents` is an array that is populated with objects representing the contents of a specified directory (e.g. the same directory where you have your template yaml). Each object in the array corresponds to a file within the directory and contains two properties; the name of the file and the content of the file, encoded in Base64. +This is needed if any other files were required by the actions your template is using. diff --git a/mkdocs.yml b/mkdocs.yml index b9f6d41d46..045238e97e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -139,6 +139,7 @@ nav: - URL Reader: 'plugins/url-reader.md' - Testing: - Testing with Jest: 'plugins/testing.md' + - Dry Run Testing: 'plugins/dry-run-testing.md' - Publishing: - Publish private: 'plugins/publish-private.md' - Add to Directory: 'plugins/add-to-directory.md' From 6f5c2482253f1ee99a3ae2f4472f24918ed9443b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:54:17 +0000 Subject: [PATCH 240/860] chore(deps): update dependency @changesets/cli to v2.27.6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 409 +++--------------------------------------------------- 1 file changed, 21 insertions(+), 388 deletions(-) diff --git a/yarn.lock b/yarn.lock index d41120ce21..85d8841703 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8038,8 +8038,8 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.27.5 - resolution: "@changesets/cli@npm:2.27.5" + version: 2.27.6 + resolution: "@changesets/cli@npm:2.27.6" dependencies: "@babel/runtime": ^7.20.1 "@changesets/apply-release-plan": ^7.0.3 @@ -8065,7 +8065,7 @@ __metadata: external-editor: ^3.1.0 fs-extra: ^7.0.1 human-id: ^1.0.2 - meow: ^6.0.0 + mri: ^1.2.0 outdent: ^0.5.0 p-limit: ^2.2.0 preferred-pm: ^3.0.0 @@ -8073,10 +8073,9 @@ __metadata: semver: ^7.5.3 spawndamnit: ^2.0.0 term-size: ^2.1.0 - tty-table: ^4.1.5 bin: changeset: bin.js - checksum: 7e0d0aadabcf3028abbb2e079b58135b8e39f78bc174f4fa669cf94482ca3a4ec873e4b4ff9a7e071d83aee592780f0c47bd36a3a12282ab5f13a493c796663f + checksum: efb3c7b569debb2bb0baae2d7bafee4ae19d3c7f0023ea97fa0b6518198c85ba16c2a66609561c9dd0f0601c3390d5933b00e3ad3cb962b4b0e7fcb4de929dfa languageName: node linkType: hard @@ -17967,13 +17966,6 @@ __metadata: languageName: node linkType: hard -"@types/normalize-package-data@npm:^2.4.0": - version: 2.4.1 - resolution: "@types/normalize-package-data@npm:2.4.1" - checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 - languageName: node - linkType: hard - "@types/npm-packlist@npm:^3.0.0": version: 3.0.0 resolution: "@types/npm-packlist@npm:3.0.0" @@ -20724,7 +20716,7 @@ __metadata: languageName: node linkType: hard -"array.prototype.flat@npm:^1.2.3, array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.2": +"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.2": version: 1.3.2 resolution: "array.prototype.flat@npm:1.3.2" dependencies: @@ -20789,13 +20781,6 @@ __metadata: languageName: node linkType: hard -"arrify@npm:^1.0.1": - version: 1.0.1 - resolution: "arrify@npm:1.0.1" - checksum: 745075dd4a4624ff0225c331dacb99be501a515d39bcb7c84d24660314a6ec28e68131b137e6f7e16318170842ce97538cd298fc4cd6b2cc798e0b957f2747e7 - languageName: node - linkType: hard - "arrify@npm:^2.0.0, arrify@npm:^2.0.1": version: 2.0.1 resolution: "arrify@npm:2.0.1" @@ -21695,15 +21680,6 @@ __metadata: languageName: node linkType: hard -"breakword@npm:^1.0.5": - version: 1.0.5 - resolution: "breakword@npm:1.0.5" - dependencies: - wcwidth: ^1.0.1 - checksum: 8ca7b10bbbbfe1c45c12c9119c4bc1e585452ddd58c5da93020a0c1deac3cf6bb335632675c9c705ba7b644065ae1d6623a25e79b7a48e0ee0ff42cb6e94b357 - languageName: node - linkType: hard - "brorand@npm:^1.0.1, brorand@npm:^1.1.0": version: 1.1.0 resolution: "brorand@npm:1.1.0" @@ -22133,17 +22109,6 @@ __metadata: languageName: node linkType: hard -"camelcase-keys@npm:^6.2.2": - version: 6.2.2 - resolution: "camelcase-keys@npm:6.2.2" - dependencies: - camelcase: ^5.3.1 - map-obj: ^4.0.0 - quick-lru: ^4.0.1 - checksum: 43c9af1adf840471e54c68ab3e5fe8a62719a6b7dbf4e2e86886b7b0ff96112c945736342b837bd2529ec9d1c7d1934e5653318478d98e0cf22c475c04658e2a - languageName: node - linkType: hard - "camelcase@npm:5.0.0": version: 5.0.0 resolution: "camelcase@npm:5.0.0" @@ -22151,7 +22116,7 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^5.0.0, camelcase@npm:^5.3.1": +"camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" checksum: e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b @@ -22573,17 +22538,6 @@ __metadata: languageName: node linkType: hard -"cliui@npm:^6.0.0": - version: 6.0.0 - resolution: "cliui@npm:6.0.0" - dependencies: - string-width: ^4.2.0 - strip-ansi: ^6.0.0 - wrap-ansi: ^6.2.0 - checksum: 4fcfd26d292c9f00238117f39fc797608292ae36bac2168cfee4c85923817d0607fe21b3329a8621e01aedf512c99b7eaa60e363a671ffd378df6649fb48ae42 - languageName: node - linkType: hard - "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -23963,39 +23917,6 @@ __metadata: languageName: node linkType: hard -"csv-generate@npm:^3.4.3": - version: 3.4.3 - resolution: "csv-generate@npm:3.4.3" - checksum: 868dc630e8bcabf42d3d1ef22c09fb783de72d7e5929854aad0323f44059b1747edf8a2724e32fdc5008396e2ea38d5c45df0b0e3a1b506e3ab34f76f3e2fb3a - languageName: node - linkType: hard - -"csv-parse@npm:^4.16.3": - version: 4.16.3 - resolution: "csv-parse@npm:4.16.3" - checksum: 5ad7790fc31c32ca1623bad1a54906134ba44fa109e8dd2dfda440bf7e9fd93610d9076a78f45c872701bfafdf7f93c9b75500c09d7efd6611d863f1d45ec69f - languageName: node - linkType: hard - -"csv-stringify@npm:^5.6.5": - version: 5.6.5 - resolution: "csv-stringify@npm:5.6.5" - checksum: f93e1444857416081de3d86765b62e4c4f7c110974ad6bbcb0031d7db39b6624847ac9ee5705726e7011346f32f3696f27299b74b23a6c2b083adff0dd2755fe - languageName: node - linkType: hard - -"csv@npm:^5.5.0": - version: 5.5.3 - resolution: "csv@npm:5.5.3" - dependencies: - csv-generate: ^3.4.3 - csv-parse: ^4.16.3 - csv-stringify: ^5.6.5 - stream-transform: ^2.1.3 - checksum: 0decc2d0d7a0abf127f4556d6f3cef5a54015b78d348608b5e8f42256c2bd0a021f34f1efc9723b2cd162680917de4c0b3967bfb65a07305eca0827654ca727e - languageName: node - linkType: hard - "ctrlc-windows@npm:^2.1.0": version: 2.1.0 resolution: "ctrlc-windows@npm:2.1.0" @@ -24282,23 +24203,6 @@ __metadata: languageName: node linkType: hard -"decamelize-keys@npm:^1.1.0": - version: 1.1.0 - resolution: "decamelize-keys@npm:1.1.0" - dependencies: - decamelize: ^1.1.0 - map-obj: ^1.0.0 - checksum: 8bc5d32e035a072f5dffc1f1f3d26ca7ab1fb44a9cade34c97ab6cd1e62c81a87e718101e96de07d78cecda20a3fdb955df958e46671ccad01bb8dcf0de2e298 - languageName: node - linkType: hard - -"decamelize@npm:^1.1.0, decamelize@npm:^1.2.0": - version: 1.2.0 - resolution: "decamelize@npm:1.2.0" - checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa - languageName: node - linkType: hard - "decimal.js@npm:^10.2.1, decimal.js@npm:^10.3.1": version: 10.4.1 resolution: "decimal.js@npm:10.4.1" @@ -27847,7 +27751,7 @@ __metadata: languageName: node linkType: hard -"get-caller-file@npm:^2.0.1, get-caller-file@npm:^2.0.5": +"get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 @@ -28527,13 +28431,6 @@ __metadata: languageName: node linkType: hard -"hard-rejection@npm:^2.1.0": - version: 2.1.0 - resolution: "hard-rejection@npm:2.1.0" - checksum: 7baaf80a0c7fff4ca79687b4060113f1529589852152fa935e6787a2bc96211e784ad4588fb3048136ff8ffc9dfcf3ae385314a5b24db32de20bea0d1597f9dc - languageName: node - linkType: hard - "harmony-reflect@npm:^1.4.6": version: 1.6.1 resolution: "harmony-reflect@npm:1.6.1" @@ -28758,13 +28655,6 @@ __metadata: languageName: node linkType: hard -"hosted-git-info@npm:^2.1.4": - version: 2.8.9 - resolution: "hosted-git-info@npm:2.8.9" - checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd - languageName: node - linkType: hard - "hosted-git-info@npm:^4.0.1": version: 4.1.0 resolution: "hosted-git-info@npm:4.1.0" @@ -30030,13 +29920,6 @@ __metadata: languageName: node linkType: hard -"is-plain-obj@npm:^1.1.0": - version: 1.1.0 - resolution: "is-plain-obj@npm:1.1.0" - checksum: 0ee04807797aad50859652a7467481816cbb57e5cc97d813a7dcd8915da8195dc68c436010bf39d195226cde6a2d352f4b815f16f26b7bf486a5754290629931 - languageName: node - linkType: hard - "is-plain-obj@npm:^3.0.0": version: 3.0.0 resolution: "is-plain-obj@npm:3.0.0" @@ -31877,7 +31760,7 @@ __metadata: languageName: node linkType: hard -"kind-of@npm:^6.0.2, kind-of@npm:^6.0.3": +"kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b @@ -31891,7 +31774,7 @@ __metadata: languageName: node linkType: hard -"kleur@npm:^4.0.3, kleur@npm:^4.1.4": +"kleur@npm:^4.0.3": version: 4.1.5 resolution: "kleur@npm:4.1.5" checksum: 1dc476e32741acf0b1b5b0627ffd0d722e342c1b0da14de3e8ae97821327ca08f9fb944542fb3c126d90ac5f27f9d804edbe7c585bf7d12ef495d115e0f22c12 @@ -32886,13 +32769,6 @@ __metadata: languageName: node linkType: hard -"map-obj@npm:^1.0.0": - version: 1.0.1 - resolution: "map-obj@npm:1.0.1" - checksum: 9949e7baec2a336e63b8d4dc71018c117c3ce6e39d2451ccbfd3b8350c547c4f6af331a4cbe1c83193d7c6b786082b6256bde843db90cb7da2a21e8fcc28afed - languageName: node - linkType: hard - "map-obj@npm:^2.0.0": version: 2.0.0 resolution: "map-obj@npm:2.0.0" @@ -32900,13 +32776,6 @@ __metadata: languageName: node linkType: hard -"map-obj@npm:^4.0.0": - version: 4.3.0 - resolution: "map-obj@npm:4.3.0" - checksum: fbc554934d1a27a1910e842bc87b177b1a556609dd803747c85ece420692380827c6ae94a95cce4407c054fa0964be3bf8226f7f2cb2e9eeee432c7c1985684e - languageName: node - linkType: hard - "markdown-it@npm:^12.2.0": version: 12.3.2 resolution: "markdown-it@npm:12.3.2" @@ -33263,25 +33132,6 @@ __metadata: languageName: node linkType: hard -"meow@npm:^6.0.0": - version: 6.1.1 - resolution: "meow@npm:6.1.1" - dependencies: - "@types/minimist": ^1.2.0 - camelcase-keys: ^6.2.2 - decamelize-keys: ^1.1.0 - hard-rejection: ^2.1.0 - minimist-options: ^4.0.2 - normalize-package-data: ^2.5.0 - read-pkg-up: ^7.0.1 - redent: ^3.0.0 - trim-newlines: ^3.0.0 - type-fest: ^0.13.1 - yargs-parser: ^18.1.3 - checksum: 77b569781145ad030be77130623d9f74d6eef0af5e0a349419d3df39bcf6d88cc25be046a7757062162a88160fb5d8604e540b5177b371d2bbc2aaf73ec01479 - languageName: node - linkType: hard - "merge-descriptors@npm:1.0.1": version: 1.0.1 resolution: "merge-descriptors@npm:1.0.1" @@ -33885,17 +33735,6 @@ __metadata: languageName: node linkType: hard -"minimist-options@npm:^4.0.2": - version: 4.1.0 - resolution: "minimist-options@npm:4.1.0" - dependencies: - arrify: ^1.0.1 - is-plain-obj: ^1.1.0 - kind-of: ^6.0.3 - checksum: 8c040b3068811e79de1140ca2b708d3e203c8003eb9a414c1ab3cd467fc5f17c9ca02a5aef23bedc51a7f8bfbe77f87e9a7e31ec81fba304cda675b019496f4e - languageName: node - linkType: hard - "minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": version: 1.2.8 resolution: "minimist@npm:1.2.8" @@ -34045,13 +33884,6 @@ __metadata: languageName: node linkType: hard -"mixme@npm:^0.5.1": - version: 0.5.4 - resolution: "mixme@npm:0.5.4" - checksum: cec5f6127c92455bc86d592f0a0628e188c7ccf3909bd106703a1d939f0e2f451ddaac6da0d77c5f14d53dd2d58f64f5b2f8ff55a68ec68be95a73d290e4d430 - languageName: node - linkType: hard - "mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": version: 0.5.3 resolution: "mkdirp-classic@npm:0.5.3" @@ -34189,7 +34021,7 @@ __metadata: languageName: node linkType: hard -"mri@npm:^1.1.0": +"mri@npm:^1.1.0, mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" checksum: 83f515abbcff60150873e424894a2f65d68037e5a7fcde8a9e2b285ee9c13ac581b63cfc1e6826c4732de3aeb84902f7c1e16b7aff46cd3f897a0f757a894e85 @@ -34879,18 +34711,6 @@ __metadata: languageName: node linkType: hard -"normalize-package-data@npm:^2.5.0": - version: 2.5.0 - resolution: "normalize-package-data@npm:2.5.0" - dependencies: - hosted-git-info: ^2.1.4 - resolve: ^1.10.0 - semver: 2 || 3 || 4 || 5 - validate-npm-package-license: ^3.0.1 - checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 - languageName: node - linkType: hard - "normalize-path@npm:^2.1.1": version: 2.1.1 resolution: "normalize-path@npm:2.1.1" @@ -37701,13 +37521,6 @@ __metadata: languageName: node linkType: hard -"quick-lru@npm:^4.0.1": - version: 4.0.1 - resolution: "quick-lru@npm:4.0.1" - checksum: bea46e1abfaa07023e047d3cf1716a06172c4947886c053ede5c50321893711577cb6119360f810cc3ffcd70c4d7db4069c3cee876b358ceff8596e062bd1154 - languageName: node - linkType: hard - "quick-lru@npm:^5.1.1": version: 5.1.1 resolution: "quick-lru@npm:5.1.1" @@ -38599,29 +38412,6 @@ __metadata: languageName: node linkType: hard -"read-pkg-up@npm:^7.0.1": - version: 7.0.1 - resolution: "read-pkg-up@npm:7.0.1" - dependencies: - find-up: ^4.1.0 - read-pkg: ^5.2.0 - type-fest: ^0.8.1 - checksum: e4e93ce70e5905b490ca8f883eb9e48b5d3cebc6cd4527c25a0d8f3ae2903bd4121c5ab9c5a3e217ada0141098eeb661313c86fa008524b089b8ed0b7f165e44 - languageName: node - linkType: hard - -"read-pkg@npm:^5.2.0": - version: 5.2.0 - resolution: "read-pkg@npm:5.2.0" - dependencies: - "@types/normalize-package-data": ^2.4.0 - normalize-package-data: ^2.5.0 - parse-json: ^5.0.0 - type-fest: ^0.6.0 - checksum: eb696e60528b29aebe10e499ba93f44991908c57d70f2d26f369e46b8b9afc208ef11b4ba64f67630f31df8b6872129e0a8933c8c53b7b4daf0eace536901222 - languageName: node - linkType: hard - "read-tls-client-hello@npm:^1.0.0": version: 1.0.1 resolution: "read-tls-client-hello@npm:1.0.1" @@ -39125,13 +38915,6 @@ __metadata: languageName: node linkType: hard -"require-main-filename@npm:^2.0.0": - version: 2.0.0 - resolution: "require-main-filename@npm:2.0.0" - checksum: e9e294695fea08b076457e9ddff854e81bffbe248ed34c1eec348b7abbd22a0d02e8d75506559e2265e96978f3c4720bd77a6dad84755de8162b357eb6c778c7 - languageName: node - linkType: hard - "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" @@ -39197,7 +38980,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1": +"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: @@ -39233,7 +39016,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.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.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: @@ -39973,15 +39756,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0, semver@npm:^5.6.0": - version: 5.7.2 - resolution: "semver@npm:5.7.2" - bin: - semver: bin/semver - checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 - languageName: node - linkType: hard - "semver@npm:7.5.4, semver@npm:~7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" @@ -39993,6 +39767,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^5.5.0, semver@npm:^5.6.0": + version: 5.7.2 + resolution: "semver@npm:5.7.2" + bin: + semver: bin/semver + checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 + languageName: node + linkType: hard + "semver@npm:^6.0.0, semver@npm:^6.2.0, semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -40483,22 +40266,6 @@ __metadata: languageName: node linkType: hard -"smartwrap@npm:^2.0.2": - version: 2.0.2 - resolution: "smartwrap@npm:2.0.2" - dependencies: - array.prototype.flat: ^1.2.3 - breakword: ^1.0.5 - grapheme-splitter: ^1.0.4 - strip-ansi: ^6.0.0 - wcwidth: ^1.0.1 - yargs: ^15.1.0 - bin: - smartwrap: src/terminal-adapter.js - checksum: 1a6833eb1c3d8488b036df66dcab37dcdda5270bb9629c471155785c09ee1b591177a9774c588c43f8fa28833204500019265da2ffed28ac7bbf4589b943d2fa - languageName: node - linkType: hard - "smol-toml@npm:^1.1.4": version: 1.2.1 resolution: "smol-toml@npm:1.2.1" @@ -40704,40 +40471,6 @@ __metadata: languageName: node linkType: hard -"spdx-correct@npm:^3.0.0": - version: 3.1.1 - resolution: "spdx-correct@npm:3.1.1" - dependencies: - spdx-expression-parse: ^3.0.0 - spdx-license-ids: ^3.0.0 - checksum: 77ce438344a34f9930feffa61be0eddcda5b55fc592906ef75621d4b52c07400a97084d8701557b13f7d2aae0cb64f808431f469e566ef3fe0a3a131dcb775a6 - languageName: node - linkType: hard - -"spdx-exceptions@npm:^2.1.0": - version: 2.3.0 - resolution: "spdx-exceptions@npm:2.3.0" - checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 - languageName: node - linkType: hard - -"spdx-expression-parse@npm:^3.0.0": - version: 3.0.1 - resolution: "spdx-expression-parse@npm:3.0.1" - dependencies: - spdx-exceptions: ^2.1.0 - spdx-license-ids: ^3.0.0 - checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde - languageName: node - linkType: hard - -"spdx-license-ids@npm:^3.0.0": - version: 3.0.12 - resolution: "spdx-license-ids@npm:3.0.12" - checksum: 92a4dddce62ce1db6fe54a7a839cf85e06abc308fc83b776a55b44e4f1906f02e7ebd506120847039e976bbbad359ea8bdfafb7925eae5cd7e73255f02e0b7d6 - languageName: node - linkType: hard - "spdy-transport@npm:^3.0.0": version: 3.0.0 resolution: "spdy-transport@npm:3.0.0" @@ -41092,15 +40825,6 @@ __metadata: languageName: node linkType: hard -"stream-transform@npm:^2.1.3": - version: 2.1.3 - resolution: "stream-transform@npm:2.1.3" - dependencies: - mixme: ^0.5.1 - checksum: 26ce872a6812d5c784fa1f042bfd403644bc1c019f64627b5012c4544830a5570bef98b47225b38120c5878b326f3d1a213cd999a2285c98b536e5e202ca5bdf - languageName: node - linkType: hard - "streamsearch@npm:^1.1.0": version: 1.1.0 resolution: "streamsearch@npm:1.1.0" @@ -42398,13 +42122,6 @@ __metadata: languageName: node linkType: hard -"trim-newlines@npm:^3.0.0": - version: 3.0.1 - resolution: "trim-newlines@npm:3.0.1" - checksum: b530f3fadf78e570cf3c761fb74fef655beff6b0f84b29209bac6c9622db75ad1417f4a7b5d54c96605dcd72734ad44526fef9f396807b90839449eb543c6206 - languageName: node - linkType: hard - "triple-beam@npm:^1.3.0, triple-beam@npm:^1.4.1": version: 1.4.1 resolution: "triple-beam@npm:1.4.1" @@ -42603,23 +42320,6 @@ __metadata: languageName: node linkType: hard -"tty-table@npm:^4.1.5": - version: 4.1.6 - resolution: "tty-table@npm:4.1.6" - dependencies: - chalk: ^4.1.2 - csv: ^5.5.0 - kleur: ^4.1.4 - smartwrap: ^2.0.2 - strip-ansi: ^6.0.0 - wcwidth: ^1.0.1 - yargs: ^17.1.1 - bin: - tty-table: adapters/terminal-adapter.js - checksum: 0f689b7d79ad6b9e608299e667a493309901fe802f1c4d66627a90cacb6fe11e0521e1a2dc5a75f793750ecdd849e98292d4874e5e6e988edd928b67045eb847 - languageName: node - linkType: hard - "tunnel-agent@npm:^0.6.0": version: 0.6.0 resolution: "tunnel-agent@npm:0.6.0" @@ -42710,20 +42410,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.6.0": - version: 0.6.0 - resolution: "type-fest@npm:0.6.0" - checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f - languageName: node - linkType: hard - -"type-fest@npm:^0.8.1": - version: 0.8.1 - resolution: "type-fest@npm:0.8.1" - checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 - languageName: node - linkType: hard - "type-fest@npm:^2.19.0": version: 2.19.0 resolution: "type-fest@npm:2.19.0" @@ -43644,16 +43330,6 @@ __metadata: languageName: node linkType: hard -"validate-npm-package-license@npm:^3.0.1": - version: 3.0.4 - resolution: "validate-npm-package-license@npm:3.0.4" - dependencies: - spdx-correct: ^3.0.0 - spdx-expression-parse: ^3.0.0 - checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad - languageName: node - linkType: hard - "validate-npm-package-name@npm:^3.0.0": version: 3.0.0 resolution: "validate-npm-package-name@npm:3.0.0" @@ -44288,13 +43964,6 @@ __metadata: languageName: node linkType: hard -"which-module@npm:^2.0.0": - version: 2.0.0 - resolution: "which-module@npm:2.0.0" - checksum: 809f7fd3dfcb2cdbe0180b60d68100c88785084f8f9492b0998c051d7a8efe56784492609d3f09ac161635b78ea29219eb1418a98c15ce87d085bce905705c9c - languageName: node - linkType: hard - "which-pm@npm:2.0.0": version: 2.0.0 resolution: "which-pm@npm:2.0.0" @@ -44684,13 +44353,6 @@ __metadata: languageName: node linkType: hard -"y18n@npm:^4.0.0": - version: 4.0.3 - resolution: "y18n@npm:4.0.3" - checksum: 014dfcd9b5f4105c3bb397c1c8c6429a9df004aa560964fb36732bfb999bfe83d45ae40aeda5b55d21b1ee53d8291580a32a756a443e064317953f08025b1aa4 - languageName: node - linkType: hard - "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -44757,16 +44419,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^18.1.2, yargs-parser@npm:^18.1.3": - version: 18.1.3 - resolution: "yargs-parser@npm:18.1.3" - dependencies: - camelcase: ^5.0.0 - decamelize: ^1.2.0 - checksum: 60e8c7d1b85814594d3719300ecad4e6ae3796748b0926137bfec1f3042581b8646d67e83c6fc80a692ef08b8390f21ddcacb9464476c39bbdf52e34961dd4d9 - languageName: node - linkType: hard - "yargs-parser@npm:^20.2.2": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9" @@ -44781,25 +44433,6 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^15.1.0": - version: 15.4.1 - resolution: "yargs@npm:15.4.1" - dependencies: - cliui: ^6.0.0 - decamelize: ^1.2.0 - find-up: ^4.1.0 - get-caller-file: ^2.0.1 - require-directory: ^2.1.1 - require-main-filename: ^2.0.0 - set-blocking: ^2.0.0 - string-width: ^4.2.0 - which-module: ^2.0.0 - y18n: ^4.0.0 - yargs-parser: ^18.1.2 - checksum: 40b974f508d8aed28598087720e086ecd32a5fd3e945e95ea4457da04ee9bdb8bdd17fd91acff36dc5b7f0595a735929c514c40c402416bbb87c03f6fb782373 - languageName: node - linkType: hard - "yargs@npm:^16.2.0": version: 16.2.0 resolution: "yargs@npm:16.2.0" From 2030962c7677f5f13b52eac8862a919ad1ec94dd Mon Sep 17 00:00:00 2001 From: Fernando Cordeiro de Lemos Date: Mon, 24 Jun 2024 09:33:29 +0200 Subject: [PATCH 241/860] Make useFacetsEntities fetches full entities from entity references EntityOwnerPicker will then display title or displayName if present for mode='owners-only'. Fixes #25348 Signed-off-by: Fernando Cordeiro de Lemos --- .changeset/metal-jokes-add.md | 5 + .../EntityOwnerPicker.test.tsx | 28 ++-- .../useFacetsEntities.test.ts | 152 ++++++++++++++---- .../EntityOwnerPicker/useFacetsEntities.ts | 43 +++-- .../CatalogPage/DefaultCatalogPage.test.tsx | 20 +++ 5 files changed, 192 insertions(+), 56 deletions(-) create mode 100644 .changeset/metal-jokes-add.md diff --git a/.changeset/metal-jokes-add.md b/.changeset/metal-jokes-add.md new file mode 100644 index 0000000000..faef714d87 --- /dev/null +++ b/.changeset/metal-jokes-add.md @@ -0,0 +1,5 @@ +--- +'@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/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx index a7b98e890f..4eb957cc16 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx @@ -395,6 +395,10 @@ describe('', () => { ], }, }); + + mockedGetEntitiesByRef.mockResolvedValue({ + items: [...ownerEntitiesBatch1, ...ownerEntitiesBatch2], + }); }); it('renders all users and groups', async () => { @@ -410,14 +414,16 @@ describe('', () => { fireEvent.click(screen.getByTestId('owner-picker-expand')); await waitFor(() => - expect(screen.getByText('another-owner')).toBeInTheDocument(), + expect(screen.getByText('Another Owner')).toBeInTheDocument(), ); - ['some-owner', 'some-owner-2', 'test-namespace/another-owner-2'].forEach( - owner => { - expect(screen.getByText(owner)).toBeInTheDocument(); - }, - ); + [ + 'some-owner', + 'Some Owner 2', + 'Another Owner in Another Namespace', + ].forEach(owner => { + expect(screen.getByText(owner)).toBeInTheDocument(); + }); expect(mockedGetEntityFacets).toHaveBeenCalledTimes(1); @@ -429,8 +435,8 @@ describe('', () => { [ 'some-owner-batch-2', - 'some-owner-2-batch-2', - 'test-namespace/another-owner-2-batch-2', + 'Some Owner Batch 2', + 'Another Owner in Another Namespace Batch 2', ].forEach(owner => { expect(screen.getByText(owner)).toBeInTheDocument(); }); @@ -470,7 +476,11 @@ describe('', () => {
    , ); - expect(mockedGetEntitiesByRef).not.toHaveBeenCalled(); + expect(mockedGetEntitiesByRef).toHaveBeenCalledWith({ + entityRefs: [...ownerEntitiesBatch1, ...ownerEntitiesBatch2].map(entity => + stringifyEntityRef(entity), + ), + }); expect(updateFilters).toHaveBeenLastCalledWith({ owners: undefined, }); diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts index 1d0d1130a6..742efaab9f 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts @@ -16,12 +16,17 @@ import { renderHook, waitFor } from '@testing-library/react'; import { useFacetsEntities } from './useFacetsEntities'; import { CatalogApi } from '@backstage/catalog-client'; +import { Entity, parseEntityRef } from '@backstage/catalog-model'; const mockedGetEntityFacets: jest.MockedFn = jest.fn(); +const mockedGetEntitiesByRefs: jest.MockedFn = + jest.fn(); + const mockCatalogApi: Partial = { getEntityFacets: mockedGetEntityFacets, + getEntitiesByRefs: mockedGetEntitiesByRefs, }; jest.mock('@backstage/core-plugin-api', () => ({ @@ -34,6 +39,31 @@ describe('useFacetsEntities', () => { jest.resetAllMocks(); }); + const facetsFromEntityRefs = (entityRefs: string[]) => ({ + facets: { + 'relations.ownedBy': entityRefs.map(value => ({ count: 1, value })), + }, + }); + + const entitiesFromEntityRefs = ( + entityRefs: string[], + enrichedEntities: { [key: string]: Entity } = {}, + ) => ({ + items: entityRefs.map(ref => { + const compoundRef = parseEntityRef(ref); + return ( + enrichedEntities[ref] || { + apiVersion: 'backstage.io/v1beta1', + kind: compoundRef.kind, + metadata: { + name: compoundRef.name, + namespace: compoundRef.namespace, + }, + } + ); + }), + }); + it(`should return empty items when facets are loading`, () => { mockedGetEntityFacets.mockReturnValue(new Promise(() => {})); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -41,14 +71,11 @@ describe('useFacetsEntities', () => { }); it(`should return the owners`, async () => { - mockedGetEntityFacets.mockResolvedValue({ - facets: { - 'relations.ownedBy': [ - { count: 1, value: 'component:default/e2' }, - { count: 1, value: 'component:default/e1' }, - ], - }, - }); + const entityRefs = ['component:default/e1', 'component:default/e2']; + mockedGetEntityFacets.mockResolvedValue(facetsFromEntityRefs(entityRefs)); + mockedGetEntitiesByRefs.mockResolvedValue( + entitiesFromEntityRefs(entityRefs), + ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -74,20 +101,46 @@ describe('useFacetsEntities', () => { }); }); - it(`should return the owners sorted by namespace, name and kind`, async () => { + it(`should return the owners sorted by namespace, (displayName or title or name) and kind`, async () => { const entityRefs = [ 'group:namespace/team-b', 'component:default/c', 'group:default/a', 'component:default/a', 'component:default/b', + 'group:default/d', + 'group:default/e', ]; - mockedGetEntityFacets.mockResolvedValue({ - facets: { - 'relations.ownedBy': entityRefs.map(value => ({ count: 1, value })), + const enrichedEntities: { [key: string]: Entity } = { + 'group:default/a': { + apiVersion: 'backstage.io/v1beta1', + kind: 'group', + metadata: { name: 'a', namespace: 'default', title: 'My title A' }, }, - }); + 'component:default/a': { + apiVersion: 'backstage.io/v1beta1', + kind: 'component', + metadata: { name: 'a', namespace: 'default', title: 'My title B' }, + }, + 'group:default/d': { + apiVersion: 'backstage.io/v1beta1', + kind: 'group', + metadata: { name: 'd', namespace: 'default' }, + spec: { profile: { displayName: 'My display name D' } }, + }, + 'group:default/e': { + apiVersion: 'backstage.io/v1beta1', + kind: 'group', + metadata: { name: 'e', namespace: 'default' }, + spec: { profile: { displayName: 'My display name E' } }, + }, + }; + + mockedGetEntityFacets.mockResolvedValue(facetsFromEntityRefs(entityRefs)); + mockedGetEntitiesByRefs.mockResolvedValue( + entitiesFromEntityRefs(entityRefs, enrichedEntities), + ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -96,16 +149,6 @@ describe('useFacetsEntities', () => { expect(result.current[0]).toEqual({ value: { items: [ - { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'a', namespace: 'default' }, - }, - { - apiVersion: 'backstage.io/v1beta1', - kind: 'group', - metadata: { name: 'a', namespace: 'default' }, - }, { apiVersion: 'backstage.io/v1beta1', kind: 'component', @@ -116,6 +159,36 @@ describe('useFacetsEntities', () => { kind: 'component', metadata: { name: 'c', namespace: 'default' }, }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'group', + metadata: { name: 'd', namespace: 'default' }, + spec: { profile: { displayName: 'My display name D' } }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'group', + metadata: { name: 'e', namespace: 'default' }, + spec: { profile: { displayName: 'My display name E' } }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'group', + metadata: { + name: 'a', + namespace: 'default', + title: 'My title A', + }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'component', + metadata: { + name: 'a', + namespace: 'default', + title: 'My title B', + }, + }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', @@ -137,11 +210,10 @@ describe('useFacetsEntities', () => { 'component:default/b', ]; - mockedGetEntityFacets.mockResolvedValue({ - facets: { - 'relations.ownedBy': entityRefs.map(value => ({ count: 1, value })), - }, - }); + mockedGetEntityFacets.mockResolvedValue(facetsFromEntityRefs(entityRefs)); + mockedGetEntitiesByRefs.mockResolvedValue( + entitiesFromEntityRefs(entityRefs), + ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -249,11 +321,25 @@ describe('useFacetsEntities', () => { 'component:default/nade', ]; - mockedGetEntityFacets.mockResolvedValue({ - facets: { - 'relations.ownedBy': entityRefs.map(value => ({ count: 1, value })), + mockedGetEntityFacets.mockResolvedValue(facetsFromEntityRefs(entityRefs)); + const enrichedEntities: { [key: string]: Entity } = { + 'group:default/go': { + apiVersion: 'backstage.io/v1beta1', + kind: 'group', + metadata: { name: 'go', namespace: 'default', title: 'Hidden Spider' }, }, - }); + 'component:default/lemon': { + apiVersion: 'backstage.io/v1beta1', + kind: 'component', + metadata: { name: 'lemon', namespace: 'default' }, + spec: { + profile: { displayName: 'Lemon Spider' }, + }, + }, + }; + mockedGetEntitiesByRefs.mockResolvedValue( + entitiesFromEntityRefs(entityRefs, enrichedEntities), + ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -262,6 +348,8 @@ describe('useFacetsEntities', () => { expect(result.current[0]).toEqual({ value: { items: [ + enrichedEntities['group:default/go'], + enrichedEntities['component:default/lemon'], { apiVersion: 'backstage.io/v1beta1', kind: 'component', diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts index 33b96d2494..10a5c5a8c2 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts @@ -17,7 +17,8 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsyncFn from 'react-use/esm/useAsyncFn'; import { catalogApiRef } from '../../api'; import { useState } from 'react'; -import { Entity, parseEntityRef } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; +import get from 'lodash/get'; type FacetsCursor = { start: number; @@ -48,29 +49,37 @@ export function useFacetsEntities({ enabled }: { enabled: boolean }) { return []; } const facet = 'relations.ownedBy'; + const facetsResponse = await catalogApi.getEntityFacets({ + facets: [facet], + }); + const entityRefs = facetsResponse.facets[facet].map(e => e.value); + return catalogApi - .getEntityFacets({ facets: [facet] }) - .then(response => - response.facets[facet] - .map(e => e.value) - .map(ref => { - const { kind, name, namespace } = parseEntityRef(ref); - return { - apiVersion: 'backstage.io/v1beta1', - kind, - metadata: { name, namespace }, - }; - }) + .getEntitiesByRefs({ entityRefs }) + .then(resp => + resp.items + .filter(entity => entity !== undefined) + .map(entity => entity as Entity) .sort( (a, b) => (a.metadata.namespace || '').localeCompare( b.metadata.namespace || '', 'en-US', ) || - a.metadata.name.localeCompare(b.metadata.name, 'en-US') || + ( + get(a, 'spec.profile.displayName') || + a.metadata.title || + a.metadata.name + ).localeCompare( + get(b, 'spec.profile.displayName') || + b.metadata.title || + b.metadata.name, + 'en-US', + ) || a.kind.localeCompare(b.kind, 'en-US'), ), ) + .then(entities => entities) .catch(() => []); }); @@ -149,6 +158,10 @@ function filterEntity(text: string, entity: Entity) { return ( entity.kind.includes(normalizedText) || entity.metadata.namespace?.includes(normalizedText) || - entity.metadata.name.includes(normalizedText) + entity.metadata.name.includes(normalizedText) || + entity.metadata.title?.includes(normalizedText) || + (get(entity, 'spec.profile.displayName') as unknown as string)?.includes( + normalizedText, + ) ); } diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index 8caaef3563..23c681a145 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -121,6 +121,26 @@ describe('DefaultCatalogPage', () => { ], }, })), + getEntitiesByRefs: jest.fn().mockImplementation(async () => ({ + items: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'not-tools', + namespace: 'default', + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'tools', + namespace: 'default', + }, + }, + ], + })), queryEntities: jest .fn() .mockImplementation(async (request: QueryEntitiesInitialRequest) => { From 5132d28818568a0c45132f9f49b49cba138a6b08 Mon Sep 17 00:00:00 2001 From: Beth Griggs Date: Fri, 21 Jun 2024 18:35:30 +0100 Subject: [PATCH 242/860] 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 243/860] 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 244/860] 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 245/860] 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 246/860] 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 247/860] 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 248/860] 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 4df96964b2014956d8b0f1dcbc12a50be4ef925f Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 4 Jun 2024 10:54:22 +0200 Subject: [PATCH 249/860] Storing the serialized workspace into google cloud bucket Signed-off-by: bnechyporenko --- .../src/scaffolder/tasks/StorageTaskBroker.ts | 28 ++---- .../src/scaffolder/tasks/WorkspaceService.ts | 90 +++++++++++++++++++ 2 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts index 03a2833938..4177780e06 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -34,6 +34,7 @@ import { AuthService, BackstageCredentials, } from '@backstage/backend-plugin-api'; +import { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService'; type TaskState = { checkpoints: { @@ -71,8 +72,8 @@ export class TaskManager implements TaskContext { storage, abortSignal, logger, + DefaultWorkspaceService.create(task, storage, config), auth, - config, ); agent.startTimeout(); return agent; @@ -84,8 +85,8 @@ export class TaskManager implements TaskContext { private readonly storage: TaskStore, private readonly signal: AbortSignal, private readonly logger: Logger, + private readonly workspaceService: WorkspaceService, private readonly auth?: AuthService, - private readonly config?: Config, ) {} get spec() { @@ -112,9 +113,7 @@ export class TaskManager implements TaskContext { taskId: string; targetPath: string; }): Promise { - if (this.isWorkspaceSerializationEnabled()) { - this.storage.rehydrateWorkspace?.(options); - } + await this.workspaceService.rehydrateWorkspace(options); } get done() { @@ -163,18 +162,11 @@ export class TaskManager implements TaskContext { } async serializeWorkspace?(options: { path: string }): Promise { - if (this.isWorkspaceSerializationEnabled()) { - await this.storage.serializeWorkspace?.({ - path: options.path, - taskId: this.task.taskId, - }); - } + await this.workspaceService.serializeWorkspace(options); } async cleanWorkspace?(): Promise { - if (this.isWorkspaceSerializationEnabled()) { - await this.storage.cleanWorkspace?.({ taskId: this.task.taskId }); - } + await this.workspaceService.cleanWorkspace(); } async complete( @@ -211,14 +203,6 @@ export class TaskManager implements TaskContext { }, 1000); } - private isWorkspaceSerializationEnabled(): boolean { - return ( - this.config?.getOptionalBoolean( - 'scaffolder.EXPERIMENTAL_workspaceSerialization', - ) ?? false - ); - } - async getInitiatorCredentials(): Promise { const secrets = this.task.secrets as InternalTaskSecrets; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts new file mode 100644 index 0000000000..15de15859d --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.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 { TaskStore } from './types'; + +import { CurrentClaimedTask } from './StorageTaskBroker'; +import { Config } from '@backstage/config'; + +type WorkspaceSerializationProvider = 'database' | 'googleCloudBucket'; + +export interface WorkspaceService { + serializeWorkspace(options: { path: string }): Promise; + + cleanWorkspace(): Promise; + + rehydrateWorkspace(options: { + taskId: string; + targetPath: string; + }): Promise; +} + +export class DefaultWorkspaceService implements WorkspaceService { + static create(task: CurrentClaimedTask, storage: TaskStore, config?: Config) { + return new DefaultWorkspaceService(task, storage, config); + } + + private constructor( + private readonly task: CurrentClaimedTask, + private readonly storage: TaskStore, + private readonly config?: Config, + ) {} + + public async serializeWorkspace(options: { path: string }): Promise { + if (this.isWorkspaceSerializationEnabled()) { + const provider = this.getWorkspaceSerializationProvider(); + switch (provider) { + case 'database': + this.storage.serializeWorkspace?.({ + path: options.path, + taskId: this.task.taskId, + }); + return; + case 'googleCloudBucket': + return; + default: + throw new Error( + `Workspace serialization provider ${provider} is not supported`, + ); + } + } + } + + public async rehydrateWorkspace(options: { + taskId: string; + targetPath: string; + }): Promise { + if (this.isWorkspaceSerializationEnabled()) { + this.storage.rehydrateWorkspace?.(options); + } + } + + public async cleanWorkspace(): Promise {} + + private isWorkspaceSerializationEnabled(): boolean { + return ( + this.config?.getOptionalBoolean( + 'scaffolder.EXPERIMENTAL_workspaceSerialization', + ) ?? false + ); + } + + private getWorkspaceSerializationProvider(): WorkspaceSerializationProvider { + return (this.config?.getOptionalString( + 'scaffolder.EXPERIMENTAL_workspaceSerializationProvider', + ) ?? 'database') as WorkspaceSerializationProvider; + } +} From 38875ed1c18cb8ec29720a95789411c5b986d819 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sun, 9 Jun 2024 23:03:25 +0200 Subject: [PATCH 250/860] Storing the serialized workspace into google cloud bucket Signed-off-by: bnechyporenko --- .../.eslintrc.js | 1 + .../CHANGELOG.md | 3 + .../README.md | 5 + .../catalog-info.yaml | 10 ++ .../knip-report.md | 2 + .../package.json | 55 +++++++++++ .../src/index.ts | 23 +++++ .../src/module.ts | 44 +++++++++ .../providers/GcpBucketWorkspaceProvider.ts | 93 +++++++++++++++++++ plugins/scaffolder-backend/config.d.ts | 9 ++ .../src/ScaffolderPlugin.ts | 10 ++ .../src/scaffolder/tasks/DatabaseTaskStore.ts | 5 +- .../tasks/DatabaseWorkspaceProvider.ts | 45 +++++++++ .../src/scaffolder/tasks/StorageTaskBroker.ts | 16 +++- .../src/scaffolder/tasks/WorkspaceService.ts | 64 +++++++------ .../scaffolder-backend/src/service/router.ts | 15 ++- plugins/scaffolder-node/api-report-alpha.md | 28 ++++++ plugins/scaffolder-node/api-report.md | 6 ++ plugins/scaffolder-node/package.json | 2 + plugins/scaffolder-node/src/alpha.ts | 44 ++++++++- plugins/scaffolder-node/src/tasks/index.ts | 2 + .../src}/tasks/serializer.test.ts | 0 .../src}/tasks/serializer.ts | 13 ++- yarn.lock | 43 +++++---- 24 files changed, 482 insertions(+), 56 deletions(-) create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/.eslintrc.js create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/README.md create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/knip-report.md create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/package.json create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/src/index.ts create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/src/module.ts create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts create mode 100644 plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseWorkspaceProvider.ts rename plugins/{scaffolder-backend/src/scaffolder => scaffolder-node/src}/tasks/serializer.test.ts (100%) rename plugins/{scaffolder-backend/src/scaffolder => scaffolder-node/src}/tasks/serializer.ts (84%) diff --git a/plugins/scaffolder-backend-module-gcp-bucket/.eslintrc.js b/plugins/scaffolder-backend-module-gcp-bucket/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md new file mode 100644 index 0000000000..b659b67db4 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md @@ -0,0 +1,3 @@ +# @backstage/plugin-scaffolder-backend-module-gcp-bucket + +## 0.0.1 diff --git a/plugins/scaffolder-backend-module-gcp-bucket/README.md b/plugins/scaffolder-backend-module-gcp-bucket/README.md new file mode 100644 index 0000000000..683dd70c01 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-scaffolder-backend-module-gcp-bucket + +The GCP bucket module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend). + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml b/plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml new file mode 100644 index 0000000000..8fac6a1a2b --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-scaffolder-backend-module-gcp-bucket + title: '@backstage/plugin-scaffolder-backend-module-gcp-bucket' + description: The GCP bucket module for @backstage/plugin-scaffolder-backend +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/scaffolder-backend-module-gcp-bucket/knip-report.md b/plugins/scaffolder-backend-module-gcp-bucket/knip-report.md new file mode 100644 index 0000000000..2661c35327 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/knip-report.md @@ -0,0 +1,2 @@ +# Knip report + diff --git a/plugins/scaffolder-backend-module-gcp-bucket/package.json b/plugins/scaffolder-backend-module-gcp-bucket/package.json new file mode 100644 index 0000000000..426d43df16 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/package.json @@ -0,0 +1,55 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-gcp-bucket", + "version": "0.0.1", + "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", + "backstage": { + "role": "backend-plugin-module" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/scaffolder-backend-module-gcp-bucket" + }, + "license": "Apache-2.0", + "exports": { + ".": "./src/index.ts", + "./package.json": "./package.json" + }, + "main": "src/index.ts", + "types": "src/index.ts", + "typesVersions": { + "*": { + "package.json": [ + "package.json" + ] + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "start": "backstage-cli package start", + "test": "backstage-cli package test" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", + "@google-cloud/storage": "^7.11.2", + "raw-body": "^2.4.1" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" + } +} diff --git a/plugins/scaffolder-backend-module-gcp-bucket/src/index.ts b/plugins/scaffolder-backend-module-gcp-bucket/src/index.ts new file mode 100644 index 0000000000..05498e3edd --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A module for the scaffolder backend that lets you interact with azure + * + * @packageDocumentation + */ + +export { gcpBucketModule as default } from './module'; diff --git a/plugins/scaffolder-backend-module-gcp-bucket/src/module.ts b/plugins/scaffolder-backend-module-gcp-bucket/src/module.ts new file mode 100644 index 0000000000..3d48b7f708 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/src/module.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 { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { scaffolderWorkspaceProviderExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; +import { GcpBucketWorkspaceProvider } from './providers/GcpBucketWorkspaceProvider'; + +/** + * @public + * The Azure Module for the Scaffolder Backend + */ +export const gcpBucketModule = createBackendModule({ + moduleId: 'gcp-bucket', + pluginId: 'scaffolder', + register({ registerInit }) { + registerInit({ + deps: { + scaffolderWorkspaceProviders: scaffolderWorkspaceProviderExtensionPoint, + config: coreServices.rootConfig, + logger: coreServices.logger, + }, + async init({ config, logger, scaffolderWorkspaceProviders }) { + scaffolderWorkspaceProviders.addProviders({ + gcpBucket: GcpBucketWorkspaceProvider.create(logger, config), + }); + }, + }); + }, +}); diff --git a/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts b/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts new file mode 100644 index 0000000000..8c132e0374 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.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 { Config } from '@backstage/config'; +import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha'; + +import getRawBody from 'raw-body'; +import { Storage } from '@google-cloud/storage'; +import { LoggerService } from '@backstage/backend-plugin-api'; + +import { + serializeWorkspace, + restoreWorkspace, +} from '@backstage/plugin-scaffolder-node'; + +export class GcpBucketWorkspaceProvider implements WorkspaceProvider { + static create(logger: LoggerService, config?: Config) { + return new GcpBucketWorkspaceProvider(new Storage(), logger, config); + } + + private constructor( + private readonly storage: Storage, + private readonly logger: LoggerService, + private readonly config?: Config, + ) {} + + public async cleanWorkspace(options: { taskId: string }): Promise { + await this.storage + .bucket(this.getGcpBucketName()) + .file(options.taskId) + .delete(); + } + + public async serializeWorkspace(options: { + path: string; + taskId: string; + }): Promise { + const fileCloud = this.storage + .bucket(this.getGcpBucketName()) + .file(options.taskId); + const workspace = await serializeWorkspace(options.path); + fileCloud.save( + workspace, + { + contentType: 'application/x-tar', + }, + err => { + if (err) { + this.logger.error( + `An error occurred during uploading the workspace of task ${ + options.taskId + } into GCP bucket ${this.getGcpBucketName()}`, + ); + } + }, + ); + } + + public async rehydrateWorkspace(options: { + taskId: string; + targetPath: string; + }): Promise { + const bucket = this.storage.bucket(this.getGcpBucketName()); + const file = bucket.file(options.taskId); + const workspace = getRawBody(file.createReadStream()); + await restoreWorkspace(options.targetPath, await workspace); + } + + private getGcpBucketName(): string { + const bucketName = this.config?.getOptionalString( + 'scaffolder.EXPERIMENTAL_gcpBucketName', + ); + if (!bucketName) { + throw new Error( + `You've missed to configure scaffolder.EXPERIMENTAL_gcpBucketName in app-config.yaml file`, + ); + } + return bucketName; + } +} diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index 754eedb55b..2e36922355 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -52,6 +52,15 @@ export interface Config { */ EXPERIMENTAL_workspaceSerialization?: boolean; + /** + * Sets the provider for workspace serialization. + * + * By default, it is your database. + */ + EXPERIMENTAL_workspaceSerializationProvider?: + | 'database' + | 'googleCloudBucket'; + /** * Every task which is in progress state and having a last heartbeat longer than a specified timeout is going to * be attempted to recover. diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index c83c6d437d..50e0dff9c0 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -33,6 +33,8 @@ import { scaffolderAutocompleteExtensionPoint, scaffolderTaskBrokerExtensionPoint, scaffolderTemplatingExtensionPoint, + scaffolderWorkspaceProviderExtensionPoint, + WorkspaceProvider, } from '@backstage/plugin-scaffolder-node/alpha'; import { createCatalogRegisterAction, @@ -84,10 +86,17 @@ export const scaffolderPlugin = createBackendPlugin({ }, }); +<<<<<<< HEAD const autocompleteHandlers: Record = {}; env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, { addAutocompleteProvider(provider) { autocompleteHandlers[provider.id] = provider.handler; +======= + const additionalWorkspaceProviders: Record = {}; + env.registerExtensionPoint(scaffolderWorkspaceProviderExtensionPoint, { + addProviders(provider) { + Object.assign(additionalWorkspaceProviders, provider); +>>>>>>> 801e5ff2007a (Storing the serialized workspace into google cloud bucket) }, }); @@ -172,6 +181,7 @@ export const scaffolderPlugin = createBackendPlugin({ discovery, permissions, autocompleteHandlers, + additionalWorkspaceProviders, }); httpRouter.use(router); }, diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index 9c95c11017..02b657032a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -40,7 +40,10 @@ import { DateTime, Duration } from 'luxon'; import { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common'; import { trimEventsTillLastRecovery } from './taskRecoveryHelper'; import { intervalFromNowTill } from './dbUtil'; -import { restoreWorkspace, serializeWorkspace } from './serializer'; +import { + restoreWorkspace, + serializeWorkspace, +} from '@backstage/plugin-scaffolder-node'; const migrationsDir = resolvePackagePath( '@backstage/plugin-scaffolder-backend', diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseWorkspaceProvider.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseWorkspaceProvider.ts new file mode 100644 index 0000000000..69f90b3d7e --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseWorkspaceProvider.ts @@ -0,0 +1,45 @@ +/* + * 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 { TaskStore } from './types'; + +import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha'; + +export class DatabaseWorkspaceProvider implements WorkspaceProvider { + static create(storage: TaskStore) { + return new DatabaseWorkspaceProvider(storage); + } + + private constructor(private readonly storage: TaskStore) {} + + public async serializeWorkspace(options: { + path: string; + taskId: string; + }): Promise { + this.storage.serializeWorkspace?.(options); + } + + public async rehydrateWorkspace(options: { + taskId: string; + targetPath: string; + }): Promise { + return this.storage.rehydrateWorkspace?.(options); + } + + public async cleanWorkspace(options: { taskId: string }): Promise { + return this.storage.cleanWorkspace?.(options); + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts index 4177780e06..f4946e6652 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -35,6 +35,7 @@ import { BackstageCredentials, } from '@backstage/backend-plugin-api'; import { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService'; +import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha'; type TaskState = { checkpoints: { @@ -66,13 +67,21 @@ export class TaskManager implements TaskContext { logger: Logger, auth?: AuthService, config?: Config, + additionalWorkspaceProviders?: Record, ) { + const workspaceService = DefaultWorkspaceService.create( + task, + storage, + additionalWorkspaceProviders, + config, + ); + const agent = new TaskManager( task, storage, abortSignal, logger, - DefaultWorkspaceService.create(task, storage, config), + workspaceService, auth, ); agent.startTimeout(); @@ -262,6 +271,10 @@ export class StorageTaskBroker implements TaskBroker { private readonly logger: Logger, private readonly config?: Config, private readonly auth?: AuthService, + private readonly additionalWorkspaceProviders?: Record< + string, + WorkspaceProvider + >, ) {} async list(options?: { @@ -350,6 +363,7 @@ export class StorageTaskBroker implements TaskBroker { this.logger, this.auth, this.config, + this.additionalWorkspaceProviders, ); } diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts index 15de15859d..69deb1c333 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Backstage Authors + * 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. @@ -14,12 +14,11 @@ * limitations under the License. */ -import { TaskStore } from './types'; - -import { CurrentClaimedTask } from './StorageTaskBroker'; import { Config } from '@backstage/config'; - -type WorkspaceSerializationProvider = 'database' | 'googleCloudBucket'; +import { CurrentClaimedTask } from './StorageTaskBroker'; +import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha'; +import { DatabaseWorkspaceProvider } from './DatabaseWorkspaceProvider'; +import { TaskStore } from './types'; export interface WorkspaceService { serializeWorkspace(options: { path: string }): Promise; @@ -33,33 +32,40 @@ export interface WorkspaceService { } export class DefaultWorkspaceService implements WorkspaceService { - static create(task: CurrentClaimedTask, storage: TaskStore, config?: Config) { - return new DefaultWorkspaceService(task, storage, config); + static create( + task: CurrentClaimedTask, + storage: TaskStore, + additionalWorkspaceProviders?: Record, + config?: Config, + ) { + const workspaceProviderName = + config?.getOptionalString( + 'scaffolder.EXPERIMENTAL_workspaceSerializationProvider', + ) ?? 'database'; + const workspaceProvider = + additionalWorkspaceProviders?.[workspaceProviderName] ?? + DatabaseWorkspaceProvider.create(storage); + return new DefaultWorkspaceService(task, workspaceProvider); } private constructor( private readonly task: CurrentClaimedTask, - private readonly storage: TaskStore, + private readonly workspaceProvider: WorkspaceProvider, private readonly config?: Config, ) {} public async serializeWorkspace(options: { path: string }): Promise { if (this.isWorkspaceSerializationEnabled()) { - const provider = this.getWorkspaceSerializationProvider(); - switch (provider) { - case 'database': - this.storage.serializeWorkspace?.({ - path: options.path, - taskId: this.task.taskId, - }); - return; - case 'googleCloudBucket': - return; - default: - throw new Error( - `Workspace serialization provider ${provider} is not supported`, - ); - } + await this.workspaceProvider.serializeWorkspace({ + path: options.path, + taskId: this.task.taskId, + }); + } + } + + public async cleanWorkspace(): Promise { + if (this.isWorkspaceSerializationEnabled()) { + await this.workspaceProvider.cleanWorkspace({ taskId: this.task.taskId }); } } @@ -68,12 +74,10 @@ export class DefaultWorkspaceService implements WorkspaceService { targetPath: string; }): Promise { if (this.isWorkspaceSerializationEnabled()) { - this.storage.rehydrateWorkspace?.(options); + await this.workspaceProvider.rehydrateWorkspace(options); } } - public async cleanWorkspace(): Promise {} - private isWorkspaceSerializationEnabled(): boolean { return ( this.config?.getOptionalBoolean( @@ -81,10 +85,4 @@ export class DefaultWorkspaceService implements WorkspaceService { ) ?? false ); } - - private getWorkspaceSerializationProvider(): WorkspaceSerializationProvider { - return (this.config?.getOptionalString( - 'scaffolder.EXPERIMENTAL_workspaceSerializationProvider', - ) ?? 'database') as WorkspaceSerializationProvider; - } } diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 3d5e49b400..769a042a78 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -94,7 +94,10 @@ import { } from '@backstage/plugin-auth-node'; import { InternalTaskSecrets } from '../scaffolder/tasks/types'; import { checkPermission } from '../util/checkPermissions'; -import { AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; +import { + AutocompleteHandler, + WorkspaceProvider, +} from '@backstage/plugin-scaffolder-node/alpha'; /** * @@ -159,6 +162,7 @@ export interface RouterOptions { taskBroker?: TaskBroker; additionalTemplateFilters?: Record; additionalTemplateGlobals?: Record; + additionalWorkspaceProviders?: Record; permissions?: PermissionsService; permissionRules?: Array< TemplatePermissionRuleInput | ActionPermissionRuleInput @@ -272,6 +276,7 @@ export async function createRouter( scheduler, additionalTemplateFilters, additionalTemplateGlobals, + additionalWorkspaceProviders, permissions, permissionRules, discovery = HostDiscovery.fromConfig(config), @@ -297,7 +302,13 @@ export async function createRouter( let taskBroker: TaskBroker; if (!options.taskBroker) { const databaseTaskStore = await DatabaseTaskStore.create({ database }); - taskBroker = new StorageTaskBroker(databaseTaskStore, logger, config, auth); + taskBroker = new StorageTaskBroker( + databaseTaskStore, + logger, + config, + auth, + additionalWorkspaceProviders, + ); if (scheduler && databaseTaskStore.listStaleTasks) { await scheduler.scheduleTask({ diff --git a/plugins/scaffolder-node/api-report-alpha.md b/plugins/scaffolder-node/api-report-alpha.md index aae32d7203..9601d73215 100644 --- a/plugins/scaffolder-node/api-report-alpha.md +++ b/plugins/scaffolder-node/api-report-alpha.md @@ -68,5 +68,33 @@ export interface ScaffolderTemplatingExtensionPoint { // @alpha export const scaffolderTemplatingExtensionPoint: ExtensionPoint; +// @alpha +export interface ScaffolderWorkspaceProviderExtensionPoint { + // (undocumented) + addProviders(providers: Record): void; +} + +// @alpha +export const scaffolderWorkspaceProviderExtensionPoint: ExtensionPoint; + +// @alpha +export interface WorkspaceProvider { + // (undocumented) + cleanWorkspace(options: { taskId: string }): Promise; + // (undocumented) + rehydrateWorkspace(options: { + taskId: string; + targetPath: string; + }): Promise; + // (undocumented) + serializeWorkspace({ + path, + taskId, + }: { + path: string; + taskId: string; + }): Promise; +} + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md index 66e8ccd678..9e9a31a991 100644 --- a/plugins/scaffolder-node/api-report.md +++ b/plugins/scaffolder-node/api-report.md @@ -256,6 +256,9 @@ export const parseRepoUrl: ( project?: string | undefined; }; +// @public +export const restoreWorkspace: (path: string, buffer?: Buffer) => Promise; + // @public (undocumented) export interface SerializedFile { // (undocumented) @@ -298,6 +301,9 @@ export type SerializedTaskEvent = { createdAt: string; }; +// @public +export const serializeWorkspace: (path: string) => Promise; + // @public export interface TaskBroker { // (undocumented) diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index ed3c016257..29dc022be1 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -61,11 +61,13 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/types": "workspace:^", + "concat-stream": "^2.0.0", "fs-extra": "^11.2.0", "globby": "^11.0.0", "isomorphic-git": "^1.23.0", "jsonschema": "^1.2.6", "p-limit": "^3.1.0", + "tar": "^6.1.12", "winston": "^3.2.1", "zod": "^3.22.4", "zod-to-json-schema": "^3.20.4" diff --git a/plugins/scaffolder-node/src/alpha.ts b/plugins/scaffolder-node/src/alpha.ts index ef4d5ab289..1bb013832c 100644 --- a/plugins/scaffolder-node/src/alpha.ts +++ b/plugins/scaffolder-node/src/alpha.ts @@ -67,6 +67,7 @@ export const scaffolderTaskBrokerExtensionPoint = */ export interface ScaffolderTemplatingExtensionPoint { addTemplateFilters(filters: Record): void; + addTemplateGlobals(filters: Record): void; } @@ -109,7 +110,7 @@ export interface ScaffolderAutocompleteExtensionPoint { } /** - * Extension point for adding template filters and globals. + * Extension point for adding autocomplete handlers. * * @alpha */ @@ -117,3 +118,44 @@ export const scaffolderAutocompleteExtensionPoint = createExtensionPoint({ id: 'scaffolder.autocomplete', }); + +/** + * This provider has to be implemented to make it possible to serialize/deserialize scaffolder workspace. + * + * @alpha + */ +export interface WorkspaceProvider { + serializeWorkspace({ + path, + taskId, + }: { + path: string; + taskId: string; + }): Promise; + + cleanWorkspace(options: { taskId: string }): Promise; + + rehydrateWorkspace(options: { + taskId: string; + targetPath: string; + }): Promise; +} + +/** + * Extension point for adding workspace providers. + * + * @alpha + */ +export interface ScaffolderWorkspaceProviderExtensionPoint { + addProviders(providers: Record): void; +} + +/** + * Extension point for adding workspace providers. + * + * @alpha + */ +export const scaffolderWorkspaceProviderExtensionPoint = + createExtensionPoint({ + id: 'scaffolder.workspace.provider', + }); diff --git a/plugins/scaffolder-node/src/tasks/index.ts b/plugins/scaffolder-node/src/tasks/index.ts index 930de95237..b1754a1f78 100644 --- a/plugins/scaffolder-node/src/tasks/index.ts +++ b/plugins/scaffolder-node/src/tasks/index.ts @@ -26,3 +26,5 @@ export type { TaskEventType, TaskStatus, } from './types'; + +export * from './serializer'; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.test.ts b/plugins/scaffolder-node/src/tasks/serializer.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/tasks/serializer.test.ts rename to plugins/scaffolder-node/src/tasks/serializer.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.ts b/plugins/scaffolder-node/src/tasks/serializer.ts similarity index 84% rename from plugins/scaffolder-backend/src/scaffolder/tasks/serializer.ts rename to plugins/scaffolder-node/src/tasks/serializer.ts index 69c48fb769..f9a55a68f4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.ts +++ b/plugins/scaffolder-node/src/tasks/serializer.ts @@ -20,13 +20,22 @@ import { promisify } from 'util'; import { pipeline as pipelineCb, Readable } from 'stream'; const pipeline = promisify(pipelineCb); - +/** + * Serializes provided path into tar archive + * + * @public + */ export const serializeWorkspace = async (path: string): Promise => { - return await new Promise(async resolve => { + return new Promise(async resolve => { await pipeline(tar.create({ cwd: path }, ['']), concatStream(resolve)); }); }; +/** + * Rehydrates the provided buffer of tar archive into the provide destination path + * + * @public + */ export const restoreWorkspace = async (path: string, buffer?: Buffer) => { if (buffer) { await pipeline( diff --git a/yarn.lock b/yarn.lock index e3cec34102..8a1a84b970 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6779,6 +6779,22 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-scaffolder-backend-module-gcp-bucket@workspace:plugins/scaffolder-backend-module-gcp-bucket": + version: 0.0.0-use.local + resolution: "@backstage/plugin-scaffolder-backend-module-gcp-bucket@workspace:plugins/scaffolder-backend-module-gcp-bucket" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/integration": "workspace:^" + "@backstage/plugin-scaffolder-node": "workspace:^" + "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" + "@google-cloud/storage": ^7.11.2 + raw-body: ^2.4.1 + languageName: unknown + linkType: soft + "@backstage/plugin-scaffolder-backend-module-gerrit@workspace:^, @backstage/plugin-scaffolder-backend-module-gerrit@workspace:plugins/scaffolder-backend-module-gerrit": version: 0.0.0-use.local resolution: "@backstage/plugin-scaffolder-backend-module-gerrit@workspace:plugins/scaffolder-backend-module-gerrit" @@ -7042,11 +7058,13 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/plugin-scaffolder-common": "workspace:^" "@backstage/types": "workspace:^" + concat-stream: ^2.0.0 fs-extra: ^11.2.0 globby: ^11.0.0 isomorphic-git: ^1.23.0 jsonschema: ^1.2.6 p-limit: ^3.1.0 + tar: ^6.1.12 winston: ^3.2.1 zod: ^3.22.4 zod-to-json-schema: ^3.20.4 @@ -9354,9 +9372,9 @@ __metadata: languageName: node linkType: hard -"@google-cloud/storage@npm:^7.0.0": - version: 7.10.1 - resolution: "@google-cloud/storage@npm:7.10.1" +"@google-cloud/storage@npm:^7.0.0, @google-cloud/storage@npm:^7.11.2": + version: 7.11.2 + resolution: "@google-cloud/storage@npm:7.11.2" dependencies: "@google-cloud/paginator": ^5.0.0 "@google-cloud/projectify": ^4.0.0 @@ -9364,16 +9382,16 @@ __metadata: abort-controller: ^3.0.0 async-retry: ^1.3.3 duplexify: ^4.1.3 - ent: ^2.2.0 fast-xml-parser: ^4.3.0 gaxios: ^6.0.2 google-auth-library: ^9.6.3 + html-entities: ^2.5.2 mime: ^3.0.0 p-limit: ^3.0.1 retry-request: ^7.0.0 teeny-request: ^9.0.0 uuid: ^8.0.0 - checksum: 0605f8abf67cde98bc48b05c749b569416af821fcc3eb8ed3fac6dc5ade9c1f2f3210404c85e30525260ea4f34785d7436f7684e6eacd083613237669badff25 + checksum: 763cd560245006e11a060fdbd5edff5d6bfe22b0c0b06dfe88af43b7b14458598c00a71c4e1b079e9ab09096d7d262bdc27fa77d76a8969af0765f23c93f8405 languageName: node linkType: hard @@ -25281,13 +25299,6 @@ __metadata: languageName: node linkType: hard -"ent@npm:^2.2.0": - version: 2.2.0 - resolution: "ent@npm:2.2.0" - checksum: f588b5707d6fef36011ea10d530645912a69530a1eb0831f8708c498ac028363a7009f45cfadd28ceb4dafd9ac17ec15213f88d09ce239cd033cfe1328dd7d7d - languageName: node - linkType: hard - "entities@npm:^2.0.0": version: 2.2.0 resolution: "entities@npm:2.2.0" @@ -28821,10 +28832,10 @@ __metadata: languageName: node linkType: hard -"html-entities@npm:^2.1.0, html-entities@npm:^2.4.0": - version: 2.4.0 - resolution: "html-entities@npm:2.4.0" - checksum: 25bea32642ce9ebd0eedc4d24381883ecb0335ccb8ac26379a0958b9b16652fdbaa725d70207ce54a51db24103436a698a8e454397d3ba8ad81460224751f1dc +"html-entities@npm:^2.1.0, html-entities@npm:^2.4.0, html-entities@npm:^2.5.2": + version: 2.5.2 + resolution: "html-entities@npm:2.5.2" + checksum: b23f4a07d33d49ade1994069af4e13d31650e3fb62621e92ae10ecdf01d1a98065c78fd20fdc92b4c7881612210b37c275f2c9fba9777650ab0d6f2ceb3b99b6 languageName: node linkType: hard From 34e70a0fbcdd9c5b6d3880711cb19fb676d3daad Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Mon, 10 Jun 2024 08:44:03 +0200 Subject: [PATCH 251/860] Storing the serialized workspace into google cloud bucket Signed-off-by: bnechyporenko --- .../api-report.md | 11 +++++++++++ plugins/scaffolder-backend/api-report.md | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 plugins/scaffolder-backend-module-gcp-bucket/api-report.md diff --git a/plugins/scaffolder-backend-module-gcp-bucket/api-report.md b/plugins/scaffolder-backend-module-gcp-bucket/api-report.md new file mode 100644 index 0000000000..b7fbc1cec1 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp-bucket/api-report.md @@ -0,0 +1,11 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-gcp-bucket" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; + +// @public +const gcpBucketModule: () => BackendFeature; +export default gcpBucketModule; +``` diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 4d75ed8421..a3beee2b53 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -64,6 +64,7 @@ import { TemplateFilter as TemplateFilter_2 } from '@backstage/plugin-scaffolder import { TemplateGlobal as TemplateGlobal_2 } from '@backstage/plugin-scaffolder-node'; import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common'; import { UrlReader } from '@backstage/backend-common'; +import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha'; import { ZodType } from 'zod'; import { ZodTypeDef } from 'zod'; @@ -477,6 +478,8 @@ export interface RouterOptions { // (undocumented) additionalTemplateGlobals?: Record; // (undocumented) + additionalWorkspaceProviders?: Record; + // (undocumented) auth?: AuthService; // (undocumented) autocompleteHandlers?: Record; @@ -559,6 +562,7 @@ export class TaskManager implements TaskContext_2 { logger: Logger, auth?: AuthService, config?: Config, + additionalWorkspaceProviders?: Record, ): TaskManager; // (undocumented) get createdBy(): string | undefined; From 80ca08eba2cdf560c25c09d1cd5833b923574a63 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 11 Jun 2024 22:32:54 +0200 Subject: [PATCH 252/860] wip Signed-off-by: bnechyporenko --- .../scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts index 69deb1c333..ab424806bf 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/WorkspaceService.ts @@ -45,7 +45,7 @@ export class DefaultWorkspaceService implements WorkspaceService { const workspaceProvider = additionalWorkspaceProviders?.[workspaceProviderName] ?? DatabaseWorkspaceProvider.create(storage); - return new DefaultWorkspaceService(task, workspaceProvider); + return new DefaultWorkspaceService(task, workspaceProvider, config); } private constructor( From 182f6f78c1de4140a15fbf2718513dc87e010dcc Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 11 Jun 2024 23:03:42 +0200 Subject: [PATCH 253/860] wip Signed-off-by: bnechyporenko --- .../providers/GcpBucketWorkspaceProvider.ts | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts b/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts index 8c132e0374..5afa267041 100644 --- a/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts +++ b/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts @@ -38,10 +38,14 @@ export class GcpBucketWorkspaceProvider implements WorkspaceProvider { ) {} public async cleanWorkspace(options: { taskId: string }): Promise { - await this.storage + const file = this.storage .bucket(this.getGcpBucketName()) - .file(options.taskId) - .delete(); + .file(options.taskId); + + const result = await file.exists(); + if (result[0]) { + await file.delete(); + } } public async serializeWorkspace(options: { @@ -52,20 +56,19 @@ export class GcpBucketWorkspaceProvider implements WorkspaceProvider { .bucket(this.getGcpBucketName()) .file(options.taskId); const workspace = await serializeWorkspace(options.path); - fileCloud.save( - workspace, - { + try { + await fileCloud.save(workspace, { contentType: 'application/x-tar', - }, - err => { - if (err) { - this.logger.error( - `An error occurred during uploading the workspace of task ${ - options.taskId - } into GCP bucket ${this.getGcpBucketName()}`, - ); - } - }, + }); + } catch (err) { + this.logger.error( + `An error occurred during uploading the workspace of task ${ + options.taskId + } into GCP bucket ${this.getGcpBucketName()}`, + ); + } + this.logger.info( + `Workspace for task ${options.taskId} has been serialized.`, ); } @@ -75,8 +78,11 @@ export class GcpBucketWorkspaceProvider implements WorkspaceProvider { }): Promise { const bucket = this.storage.bucket(this.getGcpBucketName()); const file = bucket.file(options.taskId); - const workspace = getRawBody(file.createReadStream()); - await restoreWorkspace(options.targetPath, await workspace); + const result = await file.exists(); + if (result[0]) { + const workspace = getRawBody(file.createReadStream()); + await restoreWorkspace(options.targetPath, await workspace); + } } private getGcpBucketName(): string { From 0b52438d36160776339a5ac677b7f8b56c122dc9 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 11 Jun 2024 23:13:13 +0200 Subject: [PATCH 254/860] wip Signed-off-by: bnechyporenko --- .changeset/tough-lies-mate.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/tough-lies-mate.md diff --git a/.changeset/tough-lies-mate.md b/.changeset/tough-lies-mate.md new file mode 100644 index 0000000000..cbe228a65f --- /dev/null +++ b/.changeset/tough-lies-mate.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gcp-bucket': minor +'@backstage/plugin-scaffolder-backend': minor +'@backstage/plugin-scaffolder-node': patch +--- + +Serialization of the scaffolder workspace into GCP bucket From f61f26d60899306adc7e41a110c478b42666bd12 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 13 Jun 2024 18:02:07 +0200 Subject: [PATCH 255/860] wip Signed-off-by: bnechyporenko --- .changeset/tough-lies-mate.md | 2 +- .../CHANGELOG.md | 3 --- .../catalog-info.yaml | 10 ---------- .../.eslintrc.js | 0 plugins/scaffolder-backend-module-gcp/CHANGELOG.md | 3 +++ .../README.md | 2 +- .../api-report.md | 2 +- .../scaffolder-backend-module-gcp/catalog-info.yaml | 10 ++++++++++ .../knip-report.md | 0 .../package.json | 12 +++++++----- .../src/index.ts | 0 .../src/module.ts | 2 +- .../src/providers/GcpBucketWorkspaceProvider.ts | 0 plugins/scaffolder-backend/config.d.ts | 4 +--- yarn.lock | 8 ++++---- 15 files changed, 29 insertions(+), 29 deletions(-) delete mode 100644 plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md delete mode 100644 plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/.eslintrc.js (100%) create mode 100644 plugins/scaffolder-backend-module-gcp/CHANGELOG.md rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/README.md (76%) rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/api-report.md (95%) create mode 100644 plugins/scaffolder-backend-module-gcp/catalog-info.yaml rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/knip-report.md (100%) rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/package.json (80%) rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/src/index.ts (100%) rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/src/module.ts (98%) rename plugins/{scaffolder-backend-module-gcp-bucket => scaffolder-backend-module-gcp}/src/providers/GcpBucketWorkspaceProvider.ts (100%) diff --git a/.changeset/tough-lies-mate.md b/.changeset/tough-lies-mate.md index cbe228a65f..99edcf3616 100644 --- a/.changeset/tough-lies-mate.md +++ b/.changeset/tough-lies-mate.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder-backend-module-gcp-bucket': minor +'@backstage/plugin-scaffolder-backend-module-gcp': minor '@backstage/plugin-scaffolder-backend': minor '@backstage/plugin-scaffolder-node': patch --- diff --git a/plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md deleted file mode 100644 index b659b67db4..0000000000 --- a/plugins/scaffolder-backend-module-gcp-bucket/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# @backstage/plugin-scaffolder-backend-module-gcp-bucket - -## 0.0.1 diff --git a/plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml b/plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml deleted file mode 100644 index 8fac6a1a2b..0000000000 --- a/plugins/scaffolder-backend-module-gcp-bucket/catalog-info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: backstage-plugin-scaffolder-backend-module-gcp-bucket - title: '@backstage/plugin-scaffolder-backend-module-gcp-bucket' - description: The GCP bucket module for @backstage/plugin-scaffolder-backend -spec: - lifecycle: experimental - type: backstage-backend-plugin-module - owner: maintainers diff --git a/plugins/scaffolder-backend-module-gcp-bucket/.eslintrc.js b/plugins/scaffolder-backend-module-gcp/.eslintrc.js similarity index 100% rename from plugins/scaffolder-backend-module-gcp-bucket/.eslintrc.js rename to plugins/scaffolder-backend-module-gcp/.eslintrc.js diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md new file mode 100644 index 0000000000..f633c5b8cd --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -0,0 +1,3 @@ +# @backstage/plugin-scaffolder-backend-module-gcp + +## 0.0.1 diff --git a/plugins/scaffolder-backend-module-gcp-bucket/README.md b/plugins/scaffolder-backend-module-gcp/README.md similarity index 76% rename from plugins/scaffolder-backend-module-gcp-bucket/README.md rename to plugins/scaffolder-backend-module-gcp/README.md index 683dd70c01..a9ce86cc6b 100644 --- a/plugins/scaffolder-backend-module-gcp-bucket/README.md +++ b/plugins/scaffolder-backend-module-gcp/README.md @@ -1,4 +1,4 @@ -# @backstage/plugin-scaffolder-backend-module-gcp-bucket +# @backstage/plugin-scaffolder-backend-module-gcp The GCP bucket module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend). diff --git a/plugins/scaffolder-backend-module-gcp-bucket/api-report.md b/plugins/scaffolder-backend-module-gcp/api-report.md similarity index 95% rename from plugins/scaffolder-backend-module-gcp-bucket/api-report.md rename to plugins/scaffolder-backend-module-gcp/api-report.md index b7fbc1cec1..4a3b9ebee4 100644 --- a/plugins/scaffolder-backend-module-gcp-bucket/api-report.md +++ b/plugins/scaffolder-backend-module-gcp/api-report.md @@ -1,4 +1,4 @@ -## API Report File for "@backstage/plugin-scaffolder-backend-module-gcp-bucket" +## API Report File for "@backstage/plugin-scaffolder-backend-module-gcp" > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). diff --git a/plugins/scaffolder-backend-module-gcp/catalog-info.yaml b/plugins/scaffolder-backend-module-gcp/catalog-info.yaml new file mode 100644 index 0000000000..175f9860d1 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-scaffolder-backend-module-gcp + title: '@backstage/plugin-scaffolder-backend-module-gcp' + description: The GCP module for @backstage/plugin-scaffolder-backend +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/scaffolder-backend-module-gcp-bucket/knip-report.md b/plugins/scaffolder-backend-module-gcp/knip-report.md similarity index 100% rename from plugins/scaffolder-backend-module-gcp-bucket/knip-report.md rename to plugins/scaffolder-backend-module-gcp/knip-report.md diff --git a/plugins/scaffolder-backend-module-gcp-bucket/package.json b/plugins/scaffolder-backend-module-gcp/package.json similarity index 80% rename from plugins/scaffolder-backend-module-gcp-bucket/package.json rename to plugins/scaffolder-backend-module-gcp/package.json index 426d43df16..9cb86801ef 100644 --- a/plugins/scaffolder-backend-module-gcp-bucket/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,9 +1,11 @@ { - "name": "@backstage/plugin-scaffolder-backend-module-gcp-bucket", - "version": "0.0.1", + "name": "@backstage/plugin-scaffolder-backend-module-gcp", + "version": "0.0.1-next.1", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { - "role": "backend-plugin-module" + "role": "backend-plugin-module", + "pluginId": "scaffolder", + "pluginPackage": "@backstage/plugin-scaffolder-backend" }, "publishConfig": { "access": "public" @@ -11,7 +13,7 @@ "repository": { "type": "git", "url": "https://github.com/backstage/backstage", - "directory": "plugins/scaffolder-backend-module-gcp-bucket" + "directory": "plugins/scaffolder-backend-module-gcp" }, "license": "Apache-2.0", "exports": { @@ -45,7 +47,7 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "@google-cloud/storage": "^7.11.2", + "@google-cloud/storage": "^7.0.0", "raw-body": "^2.4.1" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-gcp-bucket/src/index.ts b/plugins/scaffolder-backend-module-gcp/src/index.ts similarity index 100% rename from plugins/scaffolder-backend-module-gcp-bucket/src/index.ts rename to plugins/scaffolder-backend-module-gcp/src/index.ts diff --git a/plugins/scaffolder-backend-module-gcp-bucket/src/module.ts b/plugins/scaffolder-backend-module-gcp/src/module.ts similarity index 98% rename from plugins/scaffolder-backend-module-gcp-bucket/src/module.ts rename to plugins/scaffolder-backend-module-gcp/src/module.ts index 3d48b7f708..0f2f37f5af 100644 --- a/plugins/scaffolder-backend-module-gcp-bucket/src/module.ts +++ b/plugins/scaffolder-backend-module-gcp/src/module.ts @@ -25,7 +25,7 @@ import { GcpBucketWorkspaceProvider } from './providers/GcpBucketWorkspaceProvid * The Azure Module for the Scaffolder Backend */ export const gcpBucketModule = createBackendModule({ - moduleId: 'gcp-bucket', + moduleId: 'gcp', pluginId: 'scaffolder', register({ registerInit }) { registerInit({ diff --git a/plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts b/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts similarity index 100% rename from plugins/scaffolder-backend-module-gcp-bucket/src/providers/GcpBucketWorkspaceProvider.ts rename to plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index 2e36922355..f6b9522575 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -57,9 +57,7 @@ export interface Config { * * By default, it is your database. */ - EXPERIMENTAL_workspaceSerializationProvider?: - | 'database' - | 'googleCloudBucket'; + EXPERIMENTAL_workspaceSerializationProvider?: string; /** * Every task which is in progress state and having a last heartbeat longer than a specified timeout is going to diff --git a/yarn.lock b/yarn.lock index 8a1a84b970..3671d290fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6779,9 +6779,9 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-scaffolder-backend-module-gcp-bucket@workspace:plugins/scaffolder-backend-module-gcp-bucket": +"@backstage/plugin-scaffolder-backend-module-gcp@workspace:plugins/scaffolder-backend-module-gcp": version: 0.0.0-use.local - resolution: "@backstage/plugin-scaffolder-backend-module-gcp-bucket@workspace:plugins/scaffolder-backend-module-gcp-bucket" + resolution: "@backstage/plugin-scaffolder-backend-module-gcp@workspace:plugins/scaffolder-backend-module-gcp" dependencies: "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" @@ -6790,7 +6790,7 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" - "@google-cloud/storage": ^7.11.2 + "@google-cloud/storage": ^7.0.0 raw-body: ^2.4.1 languageName: unknown linkType: soft @@ -9372,7 +9372,7 @@ __metadata: languageName: node linkType: hard -"@google-cloud/storage@npm:^7.0.0, @google-cloud/storage@npm:^7.11.2": +"@google-cloud/storage@npm:^7.0.0": version: 7.11.2 resolution: "@google-cloud/storage@npm:7.11.2" dependencies: From c1ce17501144d5a74e70762ca9728b61d57aa33e Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sun, 16 Jun 2024 10:15:20 +0200 Subject: [PATCH 256/860] wip Signed-off-by: bnechyporenko --- .../scaffolder-backend-module-gcp/config.d.ts | 25 +++++++++++++++++++ .../package.json | 3 ++- .../providers/GcpBucketWorkspaceProvider.ts | 4 +-- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 plugins/scaffolder-backend-module-gcp/config.d.ts diff --git a/plugins/scaffolder-backend-module-gcp/config.d.ts b/plugins/scaffolder-backend-module-gcp/config.d.ts new file mode 100644 index 0000000000..acd3eebdd9 --- /dev/null +++ b/plugins/scaffolder-backend-module-gcp/config.d.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + /** Configuration options for the scaffolder plugin */ + scaffolder?: { + /** + * Sets GCP bucket name to store serialized workspace for scaffolder tasks. + */ + EXPERIMENTAL_workspaceSerializationGcpBucketName?: string; + }; +} diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 9cb86801ef..9d5efa2891 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -30,7 +30,8 @@ } }, "files": [ - "dist" + "dist", + "config.d.ts" ], "scripts": { "build": "backstage-cli package build", diff --git a/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts b/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts index 5afa267041..cd2beb2073 100644 --- a/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts +++ b/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts @@ -87,11 +87,11 @@ export class GcpBucketWorkspaceProvider implements WorkspaceProvider { private getGcpBucketName(): string { const bucketName = this.config?.getOptionalString( - 'scaffolder.EXPERIMENTAL_gcpBucketName', + 'scaffolder.EXPERIMENTAL_workspaceSerializationGcpBucketName', ); if (!bucketName) { throw new Error( - `You've missed to configure scaffolder.EXPERIMENTAL_gcpBucketName in app-config.yaml file`, + `You've missed to configure scaffolder.EXPERIMENTAL_workspaceSerializationGcpBucketName in app-config.yaml file`, ); } return bucketName; From e27d30c99c64356d68e70bd60049d255f88e6c92 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sun, 16 Jun 2024 11:45:48 +0200 Subject: [PATCH 257/860] wip Signed-off-by: bnechyporenko --- .../src/scaffolder/tasks/NunjucksWorkflowRunner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index e9b1d78e36..3b88fd0f10 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -443,7 +443,6 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { throw new Error(`Step ${step.name} has been cancelled.`); } - await task.cleanWorkspace?.(); await stepTrack.markSuccessful(); } catch (err) { await taskTrack.markFailed(step, err); @@ -513,6 +512,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { return { output }; } finally { if (workspacePath) { + await task.cleanWorkspace?.(); await fs.remove(workspacePath); } } From d9a907b062fb018ae976c548ba9d5c2cd8876128 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Mon, 24 Jun 2024 20:14:34 +0200 Subject: [PATCH 258/860] wip Signed-off-by: bnechyporenko --- plugins/scaffolder-backend-module-gcp/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 9d5efa2891..7fb3e08b34 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -54,5 +54,6 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" - } + }, + "configSchema": "config.d.ts" } From a190944647549e0444902e267c0474ef45ed0879 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 25 Jun 2024 10:25:52 +0200 Subject: [PATCH 259/860] chore: fixing api reports Signed-off-by: blam --- plugins/scaffolder-backend-module-gcp/api-report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend-module-gcp/api-report.md b/plugins/scaffolder-backend-module-gcp/api-report.md index 4a3b9ebee4..d75a6ce155 100644 --- a/plugins/scaffolder-backend-module-gcp/api-report.md +++ b/plugins/scaffolder-backend-module-gcp/api-report.md @@ -3,9 +3,9 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { BackendFeature } from '@backstage/backend-plugin-api'; +import { BackendFeatureCompat } from '@backstage/backend-plugin-api'; // @public -const gcpBucketModule: () => BackendFeature; +const gcpBucketModule: BackendFeatureCompat; export default gcpBucketModule; ``` From 47b7ac5adefd8c9039e12d3850b5e0c500286930 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 25 Jun 2024 11:43:45 +0200 Subject: [PATCH 260/860] wip Signed-off-by: bnechyporenko --- .../providers/GcpBucketWorkspaceProvider.ts | 6 ++--- .../src/scaffolder/tasks/DatabaseTaskStore.ts | 7 ++++-- .../src/tasks/serializer.test.ts | 7 ++++-- .../scaffolder-node/src/tasks/serializer.ts | 23 ++++++++++++++----- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts b/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts index cd2beb2073..3d269f690e 100644 --- a/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts +++ b/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts @@ -55,7 +55,7 @@ export class GcpBucketWorkspaceProvider implements WorkspaceProvider { const fileCloud = this.storage .bucket(this.getGcpBucketName()) .file(options.taskId); - const workspace = await serializeWorkspace(options.path); + const { contents: workspace } = await serializeWorkspace(options); try { await fileCloud.save(workspace, { contentType: 'application/x-tar', @@ -80,8 +80,8 @@ export class GcpBucketWorkspaceProvider implements WorkspaceProvider { const file = bucket.file(options.taskId); const result = await file.exists(); if (result[0]) { - const workspace = getRawBody(file.createReadStream()); - await restoreWorkspace(options.targetPath, await workspace); + const workspace = await getRawBody(file.createReadStream()); + await restoreWorkspace({ path: options.targetPath, buffer: workspace }); } } diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index 02b657032a..a4447c5dc0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -520,7 +520,10 @@ export class DatabaseTaskStore implements TaskStore { .where({ id: options.taskId }) .select('workspace'); - await restoreWorkspace(options.targetPath, result.workspace); + await restoreWorkspace({ + path: options.targetPath, + buffer: result.workspace, + }); } async cleanWorkspace({ taskId }: { taskId: string }): Promise { @@ -537,7 +540,7 @@ export class DatabaseTaskStore implements TaskStore { await this.db('tasks') .where({ id: options.taskId }) .update({ - workspace: await serializeWorkspace(options.path), + workspace: (await serializeWorkspace(options)).contents, }); } } diff --git a/plugins/scaffolder-node/src/tasks/serializer.test.ts b/plugins/scaffolder-node/src/tasks/serializer.test.ts index bec5398e28..a0ddfa624d 100644 --- a/plugins/scaffolder-node/src/tasks/serializer.test.ts +++ b/plugins/scaffolder-node/src/tasks/serializer.test.ts @@ -72,8 +72,11 @@ describe('serializer', () => { const restoredWorkspaceDir = createMockDirectory(); it('should be able to archive and restore the workspace', async () => { - const workspaceBuffer = await serializeWorkspace(workspaceDir.path); - await restoreWorkspace(restoredWorkspaceDir.path, workspaceBuffer); + const workspaceBuffer = await serializeWorkspace(workspaceDir); + await restoreWorkspace({ + path: restoredWorkspaceDir.path, + buffer: workspaceBuffer.contents, + }); expect( fs.existsSync(`${restoredWorkspaceDir.path}/\$\{ESCAPE_ME\}.txt`), diff --git a/plugins/scaffolder-node/src/tasks/serializer.ts b/plugins/scaffolder-node/src/tasks/serializer.ts index f9a55a68f4..baf1b42157 100644 --- a/plugins/scaffolder-node/src/tasks/serializer.ts +++ b/plugins/scaffolder-node/src/tasks/serializer.ts @@ -23,20 +23,31 @@ const pipeline = promisify(pipelineCb); /** * Serializes provided path into tar archive * - * @public + * @alpha */ -export const serializeWorkspace = async (path: string): Promise => { - return new Promise(async resolve => { - await pipeline(tar.create({ cwd: path }, ['']), concatStream(resolve)); +export const serializeWorkspace = async (opts: { + path: string; +}): Promise<{ contents: Buffer }> => { + return new Promise<{ contents: Buffer }>(async resolve => { + await pipeline( + tar.create({ cwd: opts.path }, ['']), + concatStream(buffer => { + return resolve({ contents: buffer }); + }), + ); }); }; /** * Rehydrates the provided buffer of tar archive into the provide destination path * - * @public + * @alpha */ -export const restoreWorkspace = async (path: string, buffer?: Buffer) => { +export const restoreWorkspace = async (opts: { + path: string; + buffer?: Buffer; +}): Promise => { + const { buffer, path } = opts; if (buffer) { await pipeline( Readable.from(buffer), From b61503b2ba0ca8c75045db71713611586c143cec Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 25 Jun 2024 14:41:42 +0200 Subject: [PATCH 261/860] feat: fix up the branch Signed-off-by: blam --- .../src/providers/GcpBucketWorkspaceProvider.ts | 2 +- .../scaffolder-backend/src/ScaffolderPlugin.ts | 6 +++--- .../src/scaffolder/tasks/DatabaseTaskStore.ts | 2 +- plugins/scaffolder-node/api-report-alpha.md | 13 +++++++++++++ plugins/scaffolder-node/api-report.md | 6 ------ plugins/scaffolder-node/src/alpha.ts | 2 ++ plugins/scaffolder-node/src/tasks/alpha.ts | 16 ++++++++++++++++ plugins/scaffolder-node/src/tasks/index.ts | 2 -- 8 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 plugins/scaffolder-node/src/tasks/alpha.ts diff --git a/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts b/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts index 3d269f690e..3529073648 100644 --- a/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts +++ b/plugins/scaffolder-backend-module-gcp/src/providers/GcpBucketWorkspaceProvider.ts @@ -24,7 +24,7 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import { serializeWorkspace, restoreWorkspace, -} from '@backstage/plugin-scaffolder-node'; +} from '@backstage/plugin-scaffolder-node/alpha'; export class GcpBucketWorkspaceProvider implements WorkspaceProvider { static create(logger: LoggerService, config?: Config) { diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index 50e0dff9c0..27b4f6b196 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -86,17 +86,17 @@ export const scaffolderPlugin = createBackendPlugin({ }, }); -<<<<<<< HEAD const autocompleteHandlers: Record = {}; env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, { addAutocompleteProvider(provider) { autocompleteHandlers[provider.id] = provider.handler; -======= + }, + }); + const additionalWorkspaceProviders: Record = {}; env.registerExtensionPoint(scaffolderWorkspaceProviderExtensionPoint, { addProviders(provider) { Object.assign(additionalWorkspaceProviders, provider); ->>>>>>> 801e5ff2007a (Storing the serialized workspace into google cloud bucket) }, }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index a4447c5dc0..fe62572af9 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -43,7 +43,7 @@ import { intervalFromNowTill } from './dbUtil'; import { restoreWorkspace, serializeWorkspace, -} from '@backstage/plugin-scaffolder-node'; +} from '@backstage/plugin-scaffolder-node/alpha'; const migrationsDir = resolvePackagePath( '@backstage/plugin-scaffolder-backend', diff --git a/plugins/scaffolder-node/api-report-alpha.md b/plugins/scaffolder-node/api-report-alpha.md index 9601d73215..c9b8130f0e 100644 --- a/plugins/scaffolder-node/api-report-alpha.md +++ b/plugins/scaffolder-node/api-report-alpha.md @@ -3,6 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { TaskBroker } from '@backstage/plugin-scaffolder-node'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; @@ -24,6 +26,12 @@ export type AutocompleteHandler = ({ }[]; }>; +// @alpha +export const restoreWorkspace: (opts: { + path: string; + buffer?: Buffer; +}) => Promise; + // @alpha export interface ScaffolderActionsExtensionPoint { // (undocumented) @@ -77,6 +85,11 @@ export interface ScaffolderWorkspaceProviderExtensionPoint { // @alpha export const scaffolderWorkspaceProviderExtensionPoint: ExtensionPoint; +// @alpha +export const serializeWorkspace: (opts: { path: string }) => Promise<{ + contents: Buffer; +}>; + // @alpha export interface WorkspaceProvider { // (undocumented) diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md index 9e9a31a991..66e8ccd678 100644 --- a/plugins/scaffolder-node/api-report.md +++ b/plugins/scaffolder-node/api-report.md @@ -256,9 +256,6 @@ export const parseRepoUrl: ( project?: string | undefined; }; -// @public -export const restoreWorkspace: (path: string, buffer?: Buffer) => Promise; - // @public (undocumented) export interface SerializedFile { // (undocumented) @@ -301,9 +298,6 @@ export type SerializedTaskEvent = { createdAt: string; }; -// @public -export const serializeWorkspace: (path: string) => Promise; - // @public export interface TaskBroker { // (undocumented) diff --git a/plugins/scaffolder-node/src/alpha.ts b/plugins/scaffolder-node/src/alpha.ts index 1bb013832c..6a0e34faf7 100644 --- a/plugins/scaffolder-node/src/alpha.ts +++ b/plugins/scaffolder-node/src/alpha.ts @@ -22,6 +22,8 @@ import { TaskBroker, } from '@backstage/plugin-scaffolder-node'; +export * from './tasks/alpha'; + /** * Extension point for managing scaffolder actions. * diff --git a/plugins/scaffolder-node/src/tasks/alpha.ts b/plugins/scaffolder-node/src/tasks/alpha.ts new file mode 100644 index 0000000000..fb6b09026c --- /dev/null +++ b/plugins/scaffolder-node/src/tasks/alpha.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export * from './serializer'; diff --git a/plugins/scaffolder-node/src/tasks/index.ts b/plugins/scaffolder-node/src/tasks/index.ts index b1754a1f78..930de95237 100644 --- a/plugins/scaffolder-node/src/tasks/index.ts +++ b/plugins/scaffolder-node/src/tasks/index.ts @@ -26,5 +26,3 @@ export type { TaskEventType, TaskStatus, } from './types'; - -export * from './serializer'; From f03d12aff20b7f536a76f664fe53f9bcd6ffdcc3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 25 Jun 2024 13:05:56 +0000 Subject: [PATCH 262/860] Version Packages (next) --- .changeset/create-app-1719320674.md | 5 + .changeset/pre.json | 48 +- docs/releases/v1.29.0-next.0-changelog.md | 2161 +++++++++++++++++ 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 | 19 + packages/backend-app-api/package.json | 2 +- packages/backend-common/CHANGELOG.md | 20 + 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 | 14 + 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 | 15 + packages/backend-test-utils/package.json | 2 +- packages/backend/CHANGELOG.md | 37 + packages/backend/package.json | 2 +- packages/cli/CHANGELOG.md | 26 + packages/cli/package.json | 2 +- packages/core-app-api/CHANGELOG.md | 23 + 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 | 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 | 10 + 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 | 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 | 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 +- 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 | 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 | 17 + .../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 | 15 + .../catalog-backend-module-ldap/package.json | 2 +- .../catalog-backend-module-logs/CHANGELOG.md | 15 + .../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 | 22 + 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 +- .../catalog-unprocessed-entities/CHANGELOG.md | 10 + .../catalog-unprocessed-entities/package.json | 2 +- plugins/catalog/CHANGELOG.md | 22 + 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/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 | 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 | 17 + 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 | 18 + 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 | 17 + 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 | 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 | 17 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../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 | 38 + 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 | 16 + plugins/scaffolder-node/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 20 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 29 + 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 | 13 + 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 | 12 + plugins/techdocs-react/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 +- yarn.lock | 264 +- 313 files changed, 4728 insertions(+), 219 deletions(-) create mode 100644 .changeset/create-app-1719320674.md create mode 100644 docs/releases/v1.29.0-next.0-changelog.md create mode 100644 plugins/catalog-backend-module-logs/CHANGELOG.md diff --git a/.changeset/create-app-1719320674.md b/.changeset/create-app-1719320674.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1719320674.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/pre.json b/.changeset/pre.json index dcb909ba99..df3592a582 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -184,7 +184,51 @@ "@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-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": [] + "changesets": [ + "bright-panthers-leave", + "calm-jeans-ring", + "chilly-roses-trade", + "clever-waves-judge", + "create-app-1719320674", + "curvy-teachers-smell", + "eighty-games-wink", + "fair-pillows-know", + "fair-rockets-leave", + "famous-dodos-crash", + "fifty-pumpkins-smell", + "friendly-masks-type", + "friendly-stingrays-occur", + "funny-laws-tease", + "gentle-avocados-obey", + "grumpy-wolves-hang", + "heavy-moose-pull", + "honest-pears-run", + "khaki-rivers-obey", + "light-avocados-worry", + "little-games-fail", + "metal-jokes-add", + "moody-llamas-breathe", + "rare-peas-dream", + "renovate-7b61228", + "rich-bears-march", + "selfish-turtles-jog", + "serious-kings-trade", + "short-flowers-cry", + "shy-hounds-battle", + "silent-experts-move", + "silent-moose-eat", + "soft-clocks-bake", + "sour-jokes-sneeze", + "ten-dancers-drum", + "ten-pots-walk", + "thick-lizards-divide", + "tough-lies-mate", + "young-donuts-swim", + "young-fishes-lie", + "young-houses-unite" + ] } diff --git a/docs/releases/v1.29.0-next.0-changelog.md b/docs/releases/v1.29.0-next.0-changelog.md new file mode 100644 index 0000000000..1ab1cfc547 --- /dev/null +++ b/docs/releases/v1.29.0-next.0-changelog.md @@ -0,0 +1,2161 @@ +# Release v1.29.0-next.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.29.0-next.0](https://backstage.github.io/upgrade-helper/?to=1.29.0-next.0) + +## @backstage/core-app-api@1.13.0-next.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 + +- 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/integration@1.13.0-next.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-scaffolder@1.22.0-next.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 + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- 89c44b3: Support `catalogFilter` array on `OwnedEntityPicker` +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/plugin-scaffolder-react@1.10.0-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/core-compat-api@0.2.7-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/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.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 + +- 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.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.3-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.11-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.13-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.11-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.19-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.11-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-permission-common@0.7.14 + - @backstage/plugin-scaffolder-common@1.5.3 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.1.0-next.2 + +### Minor Changes + +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.0 + +### Minor Changes + +- 70c4b36: Adds support for custom tag policies when creating GitHub environments. + +### Patch Changes + +- 4410fed: Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-react@1.10.0-next.0 + +### Minor Changes + +- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-app-api@1.13.0-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.9-next.0 + +### Patch Changes + +- b60db08: Fixing exporting of classes properly from new packages +- a63c4b6: Fixing issue with `MiddlewareFactory` deprecation wrapping +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-permission-node@0.7.32-next.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/types@1.1.1 + +## @backstage/backend-common@0.23.2-next.0 + +### 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 +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.3.3-next.0 + +### 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 +- cb14a05: Repack the package to fix issues with typescript with named exports +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/backend-app-api@0.7.9-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/backend-dynamic-feature-service@0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/backend-app-api@0.7.9-next.0 + - @backstage/plugin-app-node@0.1.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-catalog-backend@1.23.2-next.0 + - @backstage/plugin-events-backend@0.3.8-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/plugin-search-backend-node@1.2.26-next.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/types@1.1.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/backend-openapi-utils@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/errors@1.2.4 + +## @backstage/backend-plugin-api@0.6.21-next.0 + +### 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 +- Updated dependencies + - @backstage/plugin-auth-node@0.4.16-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-permission-common@0.7.14 + +## @backstage/backend-tasks@0.5.26-next.0 + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.4.3-next.0 + +### Patch Changes + +- fce7887: Added mock for the Root Health Service in `mockServices`. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-defaults@0.3.3-next.0 + - @backstage/backend-app-api@0.7.9-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/cli@0.26.10-next.0 + +### Patch Changes + +- 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 +- Updated dependencies + - @backstage/integration@1.13.0-next.0 + - @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/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/core-components@0.14.9-next.0 + +### Patch Changes + +- d4ffdbb: Fixed bug where `` component with empty string as placeholder gave an error +- Updated dependencies + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + ## 0.14.8 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 74cb0d7fbb..72f733e1a9 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.8", + "version": "0.14.9-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 6ab3cb0882..d6ccf478a4 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/create-app +## 0.5.17-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.14 + ## 0.5.16 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 066dad2b57..bcbb1c5899 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.16", + "version": "0.5.17-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index b28267c160..d44d840187 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/dev-utils +## 1.0.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-app-api@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/app-defaults@1.5.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/theme@0.5.6 + ## 1.0.33 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index ed887bce11..43f05d62ae 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.0.33", + "version": "1.0.34-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 4a4edf005e..74e22bcb63 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + ## 0.2.17 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 63536bc4a3..d63b93a7ba 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.17", + "version": "0.2.18-next.0", "private": true, "backstage": { "role": "cli" diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index be9eab1863..94fffd0397 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.2-next.0 + +### 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-next.0 + - @backstage/core-app-api@1.13.0-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 0.7.1 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 401fcfc529..f4290b70cc 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.1", + "version": "0.7.2-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 0ac7968290..15e3c06bd6 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-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 0.6.6 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index ad8cb41ca9..be603e2611 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.6", + "version": "0.6.7-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index db6adef523..04c896d246 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.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/test-utils@1.5.7-next.0 + - @backstage/types@1.1.1 + ## 0.1.8 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index f51df52828..c7d28e99e3 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.8", + "version": "0.1.9-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 5952b43cbd..e5e5759f1e 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 1.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.13.0-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + ## 1.1.28 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 34e91e0110..375f99fba6 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.1.28", + "version": "1.1.29-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 f50b992f3c..a76d031e35 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/integration +## 1.13.0-next.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.12.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index 56b7b1bd82..6f4743fd13 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "1.12.0", + "version": "1.13.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 aa65b502a0..204437551d 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/repo-tools +## 0.9.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @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.1 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 30f003aea5..4eca696aea 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.1", + "version": "0.9.3-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index da77dd57ad..99af9b8ad0 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.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6-next.0 + - @backstage/plugin-techdocs@1.10.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-app-api@1.13.0-next.0 + - @backstage/cli@0.26.10-next.0 + - @backstage/plugin-catalog@1.21.1-next.0 + - @backstage/app-defaults@1.5.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/test-utils@1.5.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/theme@0.5.6 + ## 0.2.97 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index ad2da35606..ef762bc3e2 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.97", + "version": "0.2.98-next.0", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 5ff165c4a9..9fa6485f0d 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,17 @@ # @techdocs/cli +## 1.8.15-next.0 + +### Patch Changes + +- c964a3d: Import discovery from backend-defaults instead of backend-common +- Updated dependencies + - @backstage/backend-defaults@0.3.3-next.0 + - @backstage/plugin-techdocs-node@1.12.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + ## 1.8.12 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 9c87235af7..e1f00726af 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.12", + "version": "1.8.15-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 893316d288..c19d0cd4af 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/test-utils +## 1.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.0-next.0 + - @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.6 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index d2294c27b6..a1e642dd89 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.5.6", + "version": "1.5.7-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 5b8e039c4e..80aaf0dbc7 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.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/plugin-catalog@1.21.1-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-react@0.4.23 + ## 0.11.6 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index b8aed9f360..5a64e41e19 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.6", + "version": "0.11.7-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 90e9a080dd..a898805ef2 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-app-backend +## 0.3.70-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-app-node@0.1.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.3.68 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 5071bdaf86..50c7d98d55 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.68", + "version": "0.3.70-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 d16d233b2c..71d34825c0 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-node +## 0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/config-loader@1.8.1 + ## 0.1.19 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index d008a82284..e7d639d620 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.19", + "version": "0.1.21-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 d30dbfc0ca..d4a23d79f2 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-app-visualizer +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.7 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 5d8f9b2649..31c7dfd87e 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.7", + "version": "0.1.8-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 ee68bd7df5..aadbd252ed 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.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index c961892674..9ceec32602 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.0", + "version": "0.2.2-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 f96de94fa6..747f13b972 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.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-backend@0.22.8-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/errors@1.2.4 + ## 0.1.11 ### 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 c65df9e16e..500914eb64 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.11", + "version": "0.1.13-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 2771262546..7067eb6b14 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.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + ## 0.1.2 ### 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 8303ada7a9..b505a45804 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.2", + "version": "0.1.4-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 3c21cc0498..f337ee2c87 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.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.1.2 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 21653b691a..70a5265b87 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.2", + "version": "0.1.4-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 781c1e2a7d..e94bb32963 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.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.2 ### 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 1d99725963..076c94b37c 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.2", + "version": "0.1.4-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 f42462e619..c593dbacf8 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.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.14 ### 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 e8932d908c..bd97b9094d 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.14", + "version": "0.2.16-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 8a050e26c3..8461d67843 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.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.1.16 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index d8d115454e..8a813883ce 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.16", + "version": "0.1.18-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 e448079c05..5d84c75f92 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.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.1.16 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 4b7117e863..4dd9548f98 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.16", + "version": "0.1.18-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 412e50d6aa..0cef76c81c 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.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.1.16 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 48271c34b9..fdf8eb6728 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.16", + "version": "0.1.18-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 79f9767571..5d9a1ac2c8 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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + ## 0.1.5 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index cf7491adf4..7f569c1f74 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.5", + "version": "0.1.7-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 2cb76d0866..48ea704e10 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.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index 598c69118c..abdb555bb1 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.14", + "version": "0.1.16-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 acec3a3065..b0d7371bbe 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.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 99a8e04c65..b3f7d2ddfe 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.0", + "version": "0.2.2-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 0223e64d35..52480f24f3 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.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/errors@1.2.4 + ## 0.1.12 ### 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 c865a15f47..717d4ba09a 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.12", + "version": "0.1.14-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 0a10e2e98b..a9f175f316 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.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-backend@0.22.8-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index c42d85652c..95c5ff49f8 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.0", + "version": "0.2.2-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 d1da6db5fa..c2fb212b1c 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.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.0.12 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index fa9dcf1ee5..16bbb79a44 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.12", + "version": "0.0.14-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 685ce0f1ff..ed302347c4 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.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index 6724e51cb7..54606d26f3 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.0", + "version": "0.1.2-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 ed5fdd4819..175d786367 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.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/config@1.2.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index f99d1baabd..0b78dc7dd1 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.13", + "version": "0.1.15-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 5d323e0319..c6b724bdd6 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.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/catalog-model@1.5.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index ff29719d22..78fbccdd1f 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.0", + "version": "0.2.2-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 6900d56b24..98454b2c65 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-auth-backend +## 0.22.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.2-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.13-next.0 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.4-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.4-next.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.4-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.16-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.18-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.18-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.18-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.2-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.14-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.2-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.14-next.0 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-catalog-node@1.12.3-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.22.6 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 85dd17d311..e14d4de6b0 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.6", + "version": "0.22.8-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 b91ce2141c..5c775a6bc3 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-node +## 0.4.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-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.14 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 4f42e80c92..c9b956def6 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.14", + "version": "0.4.16-next.0", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index c36109cb91..668f751352 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-react +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.1.3 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index c48438d465..114ecd1d55 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.3", + "version": "0.1.4-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 ccd47aa5e4..73060ebd4a 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-next.0 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/integration@1.13.0-next.0 + ## 0.2.20 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index a08b0f31bf..0e98fcc505 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.20", + "version": "0.2.21-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 e925fa7de3..bd5663758a 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.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.3-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.24 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.3.14 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 299da7d302..3b75c3cfcd 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.14", + "version": "0.3.16-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 dce335f353..598636a239 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.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.24 + ## 0.1.39 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index aa66f869a6..bf0b69f177 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.39", + "version": "0.1.41-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 7081965cc9..fa23d67c67 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.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/backend-openapi-utils@0.1.14-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index b85332a6f0..4d06de5ddb 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.2", + "version": "0.2.4-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 89f45366fa..2a977a4f7b 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.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-events-node@0.3.7-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.24 + ## 0.2.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 41285c1e49..d0261ad01f 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.6", + "version": "0.2.8-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 0724dcffab..f395e731ec 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.35-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.33 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index bff2adee0a..4d2e0a1e78 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.33", + "version": "0.1.35-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 756c77cd24..5948b92338 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.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.1.20 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 3f144c7a9c..5cfcca3ba9 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.20", + "version": "0.1.22-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 b241cbe499..5cab7509bc 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.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.36 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 207eefd381..7bac2566da 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.36", + "version": "0.1.38-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 bac2b053aa..950185b415 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.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-backend-module-github@0.6.4-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/config@1.2.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index 3946f1878c..31daeea5ee 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.14", + "version": "0.1.16-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 fb15cb0de4..d9dc710268 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.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-backend@1.23.2-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-events-node@0.3.7-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.24 + ## 0.6.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 7d3bd62281..3528786e6d 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.2", + "version": "0.6.4-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 92dc47ec69..3ce5fef0b4 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.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.20-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + ## 0.0.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index 781dc54706..0861d4ec92 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.2", + "version": "0.0.4-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 ec7bbc1c27..6fd86bb15d 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.20-next.0 + +### Patch Changes + +- 8db30ad: The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab..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.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.24 + ## 0.3.18 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index d52b452122..51538cc178 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.18", + "version": "0.3.20-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 424baa2321..04da7cc46e 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.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-backend@1.23.2-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.14 + ## 0.4.24 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index eba5fc86c1..2941fcd3f4 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.24", + "version": "0.4.26-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 62b8849ced..b975322d0d 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.6.2-next.0 + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-node@1.12.3-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.24 + ## 0.6.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index beacc5e37f..f719673682 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.0", + "version": "0.6.2-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 new file mode 100644 index 0000000000..7e5ae51a99 --- /dev/null +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -0,0 +1,15 @@ +# @backstage/plugin-catalog-backend-module-logs + +## 0.0.1-next.0 + +### 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.6.21-next.0 + - @backstage/plugin-catalog-backend@1.23.2-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index 858f7ec198..e0d2e46c78 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.0", + "version": "0.0.1-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 998f9aacd0..0f74e4591b 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.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.24 + ## 0.5.27 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index bdaa470dea..7ba2b7e1e6 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.27", + "version": "0.5.29-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 f60ec12844..8003dc39ac 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.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-backend@1.23.2-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + ## 0.1.37 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index c05d8dcec4..7016701fc0 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.37", + "version": "0.1.39-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 e990331ee9..4e5b25479a 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.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-node@1.12.3-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.25 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 3407a6dedd..1759eebb14 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.25", + "version": "0.1.27-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 a73ea9fbaf..df4e93de73 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.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-scaffolder-common@1.5.3 + ## 0.1.17 ### 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 247dc999db..a2891d2d4d 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.17", + "version": "0.1.19-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 c07c7ef7a3..6940a04db9 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.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.2 + - @backstage/plugin-permission-common@0.7.14 + ## 0.4.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 845f5aa9c6..582be2ffe8 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.6", + "version": "0.4.8-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 7b83c21930..16442df3c1 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend +## 1.23.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/backend-openapi-utils@0.1.14-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.27-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.24 + - @backstage/plugin-permission-common@0.7.14 + ## 1.23.0 ### Minor Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 574e1c99ea..d9bc71ae91 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.0", + "version": "1.23.2-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 9f39daa276..c632769632 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.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + ## 0.4.6 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 17013d199a..82f3e5d171 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.6", + "version": "0.4.7-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 9bee65367a..bbb56b6f08 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.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/core-compat-api@0.2.7-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/plugin-catalog-common@1.0.24 + ## 0.12.0 ### Minor Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 2b93e0a7c0..1082f08113 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.0", + "version": "0.12.1-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 f476ca301a..f23bfa9917 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-node +## 1.12.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-permission-node@0.7.32-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.24 + - @backstage/plugin-permission-common@0.7.14 + ## 1.12.1 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index c6bb7854b6..293b915eea 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.1", + "version": "1.12.3-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 f4e0b0c708..892bfe306d 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.0 + +### Patch Changes + +- 2030962: Make EntityOwnerPicker display metadata.title or spec.profile.displayName for mode=only-owners instead of metadata.name +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-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/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.1 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 961dad0e0e..8267047b2d 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.1", + "version": "1.12.2-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 8d39848d54..ab22634257 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-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + ## 0.2.5 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 32abaa1bbb..f32ff293df 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.5", + "version": "0.2.6-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index f74c71e66c..9c6031799c 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog +## 1.21.1-next.0 + +### Patch Changes + +- d133eaa: Added small notes to AboutCard to discourage customizability PRs +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/core-compat-api@0.2.7-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/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.0 ### Minor Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 5b7aea1449..7cafc9cf92 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.21.0", + "version": "1.21.1-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 582368aca4..76472b69b4 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-config-schema +## 0.1.57-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.1.56 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 0aa4d1dc6c..38db6a21d5 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.56", + "version": "0.1.57-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 fbcae07d37..94c827d2f3 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-devtools-backend +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @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 + ## 0.3.5 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 106950a4a4..f15e205bca 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.5", + "version": "0.3.7-next.0", "backstage": { "role": "backend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index db8e1701f1..977e9cd73f 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-devtools +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/plugin-devtools-common@0.1.10 + - @backstage/plugin-permission-react@0.4.23 + ## 0.1.15 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 3e9d697965..2749bbeef2 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.15", + "version": "0.1.16-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 0c80bac266..677cdddcfc 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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.3.5 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 6d58fe4436..9cba8e76e3 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.5", + "version": "0.3.7-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 22171cbd33..cea3fab2b6 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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + ## 0.2.5 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index bb0bce7753..74573116d7 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.5", + "version": "0.2.7-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 b71ef0dadf..eac1919f41 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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + ## 0.2.5 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 83e5f3528b..471ecb4ae2 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.5", + "version": "0.2.7-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 4ff865f60b..cb5ac5662f 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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + ## 0.2.5 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 5fbc339191..dbff36987a 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.5", + "version": "0.2.7-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 77882e3711..e2511f76ba 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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/config@1.2.0 + ## 0.2.5 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index cf1bb2c7a5..126da9f29c 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.5", + "version": "0.2.7-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 ec96ba8f73..89d2f47c10 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.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/config@1.2.0 + ## 0.2.5 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index e6ed2d9b16..45a9637a24 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.5", + "version": "0.2.7-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 4f04a9c277..e0f42a6f24 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.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.7-next.0 + ## 0.1.29 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 89dffd2e2c..931cb89248 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.29", + "version": "0.1.31-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 a5699c8d9f..a0e1f91a23 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend +## 0.3.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/config@1.2.0 + ## 0.3.6 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index d3ff69d254..b176044bf9 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.6", + "version": "0.3.8-next.0", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 18da615383..1c5025b788 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-node +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + ## 0.3.5 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 5e0e375d48..58790c4e02 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.5", + "version": "0.3.7-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 c3bb326175..f42ba59723 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.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/errors@1.2.4 + ## 1.0.28 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 36bd9f86c6..ec37ce2843 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.28", + "version": "1.0.29-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 43873757cf..2f392e6c33 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-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 1.0.28 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 5e5f76ec6b..c0ef80b3de 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.28", + "version": "1.0.29-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 4ac5fa4b93..62f3d98623 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-home-react +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.14 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index ad2bf6c7b2..819c87e20d 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.14", + "version": "0.1.15-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 fc163b8757..b6ff8061f2 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-home +## 0.7.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-app-api@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/plugin-home-react@0.1.15-next.0 + - @backstage/core-compat-api@0.2.7-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/theme@0.5.6 + ## 0.7.5 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 6dda6cbfc2..d6fbc13d29 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.7.5", + "version": "0.7.6-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 5d0b4c6f37..ea2049d73c 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-backend +## 0.18.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-kubernetes-node@0.1.15-next.0 + - @backstage/plugin-permission-node@0.7.32-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-kubernetes-common@0.8.0 + - @backstage/plugin-permission-common@0.7.14 + ## 0.18.0 ### Minor Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index ad05c481c0..d0de031d9d 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.0", + "version": "0.18.2-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 e27d874ccc..cef2c059d1 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.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/plugin-kubernetes-react@0.4.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.0.12 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 9555fdbf79..ce1fa2bc63 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.12", + "version": "0.0.13-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 47a7fbba76..6f6306cda6 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-node +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 90fb172405..2b4d061ba7 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.13", + "version": "0.1.15-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 8ebe85459a..81b5c62fad 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-react +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.4.0 ### Minor Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 481b264d27..0cc34da7db 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.0", + "version": "0.4.1-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 2320219483..5c8c4d6d4b 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes +## 0.11.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/plugin-kubernetes-react@0.4.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.11.11 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 339e26a246..998bae3626 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.11.11", + "version": "0.11.12-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 30862ed64e..60725d15ee 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.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-notifications-node@0.2.2-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.4 + ## 0.1.0 ### Minor Changes diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index 4f2c8a6876..76bf5432e2 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.0", + "version": "0.1.2-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 66885a07bd..c42aa95a2e 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-notifications-backend +## 0.3.2-next.0 + +### Patch Changes + +- d7b8ca5: Added an option to filter notifications by topic +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/plugin-notifications-node@0.2.2-next.0 + - @backstage/plugin-signals-node@0.1.7-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-notifications-common@0.0.4 + ## 0.3.0 ### Minor Changes diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index 34fe472f42..63b3b263b1 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.0", + "version": "0.3.2-next.0", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index 5611c7c6c4..041d0c355f 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-notifications-node +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-signals-node@0.1.7-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.4 + ## 0.2.0 ### Minor Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index 973182be4e..e79b457965 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.0", + "version": "0.2.2-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 3b3def49cc..ebcacf97f6 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-notifications +## 0.2.3-next.0 + +### Patch Changes + +- 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.2 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index f375ae702e..bc868c56a1 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.2.2", + "version": "0.2.3-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 9d0ffacd97..8c2ea470da 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.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + ## 0.1.25 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 32d46ef1a3..7bde5d9e9a 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.25", + "version": "0.1.26-next.0", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index e14b1afcec..fe82d2c948 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-org +## 0.6.27-next.0 + +### Patch Changes + +- 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-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.24 + ## 0.6.26 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index af3c54f1a2..5b749ac215 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.26", + "version": "0.6.27-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 3c0a8d1bcb..9192850893 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.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/plugin-permission-common@0.7.14 + ## 0.1.16 ### 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 e0108c6541..62a3f6d101 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.16", + "version": "0.1.18-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 baaaefef70..d7190f15ee 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-backend +## 0.5.45-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.14 + ## 0.5.43 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index a3020e1dd3..24b62d1358 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.43", + "version": "0.5.45-next.0", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 2e12639437..7255dbe266 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-node +## 0.7.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.14 + ## 0.7.30 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 1c29b97db0..695e28f30b 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.30", + "version": "0.7.32-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 deeaf2621b..d57f4936fb 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-proxy-backend +## 0.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.5.0 ### Minor Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 4b990e57f7..18ad338131 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.0", + "version": "0.5.2-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 7c1115e7fa..99ff7bd723 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.13-next.0 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index ece29a8866..672689ef73 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.11", + "version": "0.1.13-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 01bcce124f..f4453bab7a 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.11-next.0 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.9 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index e54f255094..d4432ee3d5 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.9", + "version": "0.1.11-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 3eefd69ab7..f614b16994 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.11-next.0 + +### 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.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.9 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index cc321ccd33..16ce106570 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.9", + "version": "0.1.11-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 97b68baf15..dc3a0f1597 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.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.11-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.11-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.9 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index bc3a578fdb..35b23e39d9 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.9", + "version": "0.2.11-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 45cb0bc6fc..d24746f67a 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.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.20 ### 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 02fa559e56..34e49f740f 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.20", + "version": "0.2.22-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 8df8ef83e5..dfa740b4a6 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.45-next.0 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.43 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index a6e9cfbf66..ea0a7fad77 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.43", + "version": "0.2.45-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 f633c5b8cd..5afcde9965 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,3 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.1.0-next.2 + +### Minor Changes + +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.0.1 diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 7fb3e08b34..2f8f130d39 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.0.1-next.1", + "version": "0.1.0-next.2", "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 2703b15871..cc4d9612a1 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.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 15aac0cceb..06c5d063d4 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.11", + "version": "0.1.13-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 d2604729c2..5f26aa6a2d 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.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.9 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 55f948b87e..f6563795cd 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.9", + "version": "0.1.11-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 16d121113e..e3cd0904aa 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.0 + +### Minor Changes + +- 70c4b36: Adds support for custom tag policies when creating GitHub environments. + +### Patch Changes + +- 4410fed: Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.3.0 ### Minor Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index c86a10fb49..1fd404c6f9 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.3.0", + "version": "0.4.0-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 eb1386679c..c64aa0ca32 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.3-next.0 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.4.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 096cf9d077..7444bde77d 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.1", + "version": "0.4.3-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 a1828b9546..948770e600 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.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/plugin-notifications-node@0.2.2-next.0 + - @backstage/plugin-notifications-common@0.0.4 + ## 0.0.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index 8f9c150d1b..bb8b7807e8 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.2", + "version": "0.0.4-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 5bf7ac953b..afaebde648 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.38-next.0 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.36 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 9da87efa1d..a736106df1 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.36", + "version": "0.4.38-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 922b8fd274..fa7712e500 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.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.27 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index efde9aa2fe..7943de9b5c 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.27", + "version": "0.1.29-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 7be229cdea..c3c2322b9a 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.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.8-next.0 + - @backstage/types@1.1.1 + ## 0.3.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index be380ac160..70133616ef 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.2", + "version": "0.3.5-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index fa81406ba0..5737dc0165 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend +## 1.23.0-next.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 + +- 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.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.3-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.11-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.13-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.11-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.19-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.11-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.11-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-permission-common@0.7.14 + - @backstage/plugin-scaffolder-common@1.5.3 + ## 1.22.9 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 9730ee78bb..c9c19d9983 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "1.22.9", + "version": "1.23.0-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 ebdf3092b7..1136cce04b 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.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-scaffolder-node@0.4.7-next.0 + - @backstage/backend-test-utils@0.4.3-next.0 + - @backstage/types@1.1.1 + ## 0.1.5 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index e15b33dad3..87f895efc3 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.5", + "version": "0.1.8-next.0", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index f5da44ae1e..f0deb319ff 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-scaffolder-node +## 0.4.7-next.0 + +### 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.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.3 + ## 0.4.5 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 29dc022be1..2568809647 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.5", + "version": "0.4.7-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 666fe36e24..baa34dbc5b 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-scaffolder-react +## 1.10.0-next.0 + +### Minor Changes + +- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-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.9.0 ### Minor Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 4bb86ca98d..6e37ff3e71 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.9.0", + "version": "1.10.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 43e1d5eab7..55d7271807 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-scaffolder +## 1.22.0-next.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 + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- 89c44b3: Support `catalogFilter` array on `OwnedEntityPicker` +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/plugin-scaffolder-react@1.10.0-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/core-compat-api@0.2.7-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/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.21.0 ### Minor Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 50cbda8e31..4cce0a83ce 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.21.0", + "version": "1.22.0-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 7e14c40bd6..e2d6440c94 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.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-search-backend-node@1.2.26-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.24 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.25 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 7c1d8cb0c0..d46e220029 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.25", + "version": "0.1.27-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 5a2d59e43e..16cf473283 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.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-search-backend-node@1.2.26-next.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.12 + ## 1.5.0 ### Minor Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 6f5d8e3b02..57414ec6e5 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.0", + "version": "1.5.2-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 f16e3019c3..4b75d163f9 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.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-search-backend-node@1.2.26-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.25 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index d1960f1f01..13cba189e5 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.25", + "version": "0.1.27-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 bd0d338f71..376d266f8f 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.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-app-api@0.7.9-next.0 + - @backstage/plugin-search-backend-node@1.2.26-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-common@1.2.12 + ## 0.5.28 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 114fde5f37..3319d85dbb 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.28", + "version": "0.5.31-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 a435215096..91652d5543 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.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-search-backend-node@1.2.26-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.12 ### 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 c817100356..60b658a34a 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.12", + "version": "0.1.14-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 e6ec7acec3..4e7e3c4baa 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.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @backstage/plugin-catalog-node@1.12.3-next.0 + - @backstage/plugin-search-backend-node@1.2.26-next.0 + - @backstage/plugin-techdocs-node@1.12.7-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.24 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.24 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index ffb4eb0042..1650012d93 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.24", + "version": "0.1.26-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 9ff9f409e7..5209cb8753 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.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-tasks@0.5.26-next.0 + - @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.24 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 4298ea10ff..ef655ac566 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.24", + "version": "1.2.26-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 56191eb595..ea4142e583 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search-backend +## 1.5.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-defaults@0.3.3-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/backend-openapi-utils@0.1.14-next.0 + - @backstage/plugin-permission-node@0.7.32-next.0 + - @backstage/plugin-search-backend-node@1.2.26-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-common@1.2.12 + ## 1.5.10 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 513446f170..c1d536d4d4 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.10", + "version": "1.5.13-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 a8e19d9649..19ace29f0c 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-react +## 1.7.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/frontend-plugin-api@0.6.7-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.12 + ## 1.7.12 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index d2496923d3..25bc946bd4 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.12", + "version": "1.7.13-next.0", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 97f03fb61e..effe205170 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search +## 1.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/core-compat-api@0.2.7-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.12 + ## 1.4.12 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 68279bfab6..f25bff3e26 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.12", + "version": "1.4.13-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 068c2be032..1e9c57e1da 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-signals-backend +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/plugin-signals-node@0.1.7-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.1.5 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index 420a5f7a93..9501878d87 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.5", + "version": "0.1.7-next.0", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index 825a9f9e04..28db4b57fa 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-signals-node +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-events-node@0.3.7-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.1.5 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 3a000d8fdd..8185c27d6b 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.5", + "version": "0.1.7-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 406f2d5a2d..f5992789c5 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-signals +## 0.0.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-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.7 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index bda5c4bcac..18345295b5 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.7", + "version": "0.0.8-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 323053ee29..93552868b9 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.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6-next.0 + - @backstage/plugin-techdocs@1.10.7-next.0 + - @backstage/core-app-api@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/plugin-catalog@1.21.1-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/test-utils@1.5.7-next.0 + ## 1.0.33 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index e21b7efdab..a18bfea16f 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.33", + "version": "1.0.34-next.0", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 2bfb317da5..286ea77341 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-techdocs-backend +## 1.10.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.26-next.0 + - @backstage/plugin-techdocs-node@1.12.7-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.24 + - @backstage/plugin-permission-common@0.7.14 + ## 1.10.6 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 081b8ab46d..01891b83d4 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.6", + "version": "1.10.8-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 50fc80dc51..da76210708 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-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 1.1.11 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 1bc6b81393..f0b2301dfb 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.11", + "version": "1.1.12-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 5eb1e136d5..0093f6a1eb 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-node +## 1.12.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/integration@1.13.0-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.12 + ## 1.12.5 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index ea88766af8..ae11fcb1df 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.5", + "version": "1.12.7-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 19fce86d6f..d07ed27eb0 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-react +## 1.2.6-next.0 + +### Patch Changes + +- 8ac9ce5: 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. +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/version-bridge@1.0.8 + ## 1.2.5 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index 05bd66a014..d002db68d1 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.5", + "version": "1.2.6-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 3701cb652d..fd35205da8 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-techdocs +## 1.10.7-next.0 + +### Patch Changes + +- 8ac9ce5: 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. +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-auth-react@0.1.4-next.0 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/plugin-search-common@1.2.12 + ## 1.10.6 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 194a8575d0..8212246aab 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.10.6", + "version": "1.10.7-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 489315b458..cbd2ab7536 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.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.21-next.0 + - @backstage/backend-common@0.23.2-next.0 + - @backstage/plugin-auth-node@0.4.16-next.0 + - @backstage/plugin-signals-node@0.1.7-next.0 + - @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.18 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 556b0d3e4a..d8dc0770a5 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.18", + "version": "0.2.20-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 bde8fa4408..20ef229a2d 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-user-settings +## 0.8.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-app-api@1.13.0-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/core-compat-api@0.2.7-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.7 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 05d594d85e..3257de8072 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.7", + "version": "0.8.8-next.0", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/yarn.lock b/yarn.lock index 3671d290fc..d396102ee2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3838,7 +3838,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: @@ -3851,7 +3851,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: @@ -4103,7 +4103,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: @@ -4175,7 +4175,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.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": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: @@ -4246,58 +4346,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: @@ -4444,6 +4493,26 @@ __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" @@ -4507,6 +4576,24 @@ __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" @@ -4531,6 +4618,23 @@ __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" @@ -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.24, @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.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": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -6568,7 +6708,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@^0.7.14, @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: @@ -6606,7 +6746,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.23, @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: @@ -7927,7 +8067,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: @@ -7958,7 +8098,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 37413c762fcc59eb1e2cbf47ef5bdce4a1f8b2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 25 Jun 2024 15:45:59 +0200 Subject: [PATCH 263/860] OWNERS.md: add org member parsifal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- OWNERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS.md b/OWNERS.md index 1437629881..9382b38f4f 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -187,6 +187,7 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling. | Mark Avery | Cvent | [webark](https://github.com/webark) | `webark#8471` | | Miklós Kiss | Roadie.io | [kissmikijr](https://github.com/kissmikijr) | `Miklos#7416` | | Patrick Jungermann | Bonial International GmbH | [pjungermann](https://github.com/pjungermann) | `pjungermann#6933` | +| Peter Macdonald | VodafoneZiggo | [Parsifal-M](https://github.com/Parsifal-M) | `parsifal` | | Phil Kuang | FactSet Research Systems | [kuangp](https://github.com/kuangp) | `pkuang#3202` | | Sebastian Poxhofer | N26 | [secustor](https://github.com/secustor) | `secustor` | | Taras Mankovski | Frontside | [taras](https://github.com/taras) | `tarasm#1256` | From f9cdc108ec08d80490ac427e8fea2476a609726f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 26 Jun 2024 10:46:32 +0200 Subject: [PATCH 264/860] add vacation note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 47ae539b6b..b422aec5fd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ [![headline](docs/assets/headline.png)](https://backstage.io/) +> [!NOTE] +> 🏖 From July 1st through 16th, due to maintainers being on summer vacations, expect the project to move a little slower than normal, and support to be limited. Normal service will resume after that! 🏝 + # [Backstage](https://backstage.io) English \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) From e8c2fbb9ed28818cec130faab8b10a299d9f0ef1 Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Wed, 26 Jun 2024 10:59:30 +0200 Subject: [PATCH 265/860] 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 60caa9216d4becc5b93ca82ede7b6021c3ac9032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 26 Jun 2024 12:05:44 +0200 Subject: [PATCH 266/860] techdocs: fix double scroll bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/metal-parents-brush.md | 5 +++++ .../techdocs/src/reader/transformers/styles/rules/layout.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changeset/metal-parents-brush.md diff --git a/.changeset/metal-parents-brush.md b/.changeset/metal-parents-brush.md new file mode 100644 index 0000000000..f73b0040fd --- /dev/null +++ b/.changeset/metal-parents-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Fix double scrollbar bug in reader diff --git a/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts b/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts index d78f8222f8..78b73cb52a 100644 --- a/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts +++ b/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts @@ -74,6 +74,7 @@ export default ({ theme, sidebar }: RuleOptions) => ` } .md-sidebar .md-sidebar__scrollwrap { width: calc(12.1rem); + overflow-y: hidden; } .md-sidebar--secondary { right: ${theme.spacing(3)}px; @@ -234,7 +235,7 @@ export default ({ theme, sidebar }: RuleOptions) => ` #toggle-sidebar { display: none; } - + .md-content { margin: 0; width: 100%; From 5177f6f0e1ce1b453f0975eea0c0a49e6c3783c2 Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Fri, 31 May 2024 12:35:40 +0200 Subject: [PATCH 267/860] User documentation for the Notifications and Signals Signed-off-by: Marek Libra --- docs/notifications/getting-started.md | 168 +++++++++++++++++++++++ docs/notifications/notificationsPage.png | Bin 0 -> 137787 bytes 2 files changed, 168 insertions(+) create mode 100644 docs/notifications/getting-started.md create mode 100644 docs/notifications/notificationsPage.png diff --git a/docs/notifications/getting-started.md b/docs/notifications/getting-started.md new file mode 100644 index 0000000000..6a7ea6314e --- /dev/null +++ b/docs/notifications/getting-started.md @@ -0,0 +1,168 @@ +--- +id: getting-started +title: Getting Started +description: How to get started with the notifications and signals +--- + +The Backstage Notifications System provides a way for plugins and external services to send notifications to Backstage users. +These notifications are displayed in the dedicated page of the Backstage frontend UI or by frontend plugins per specific scenarios. +Additionally, plugins can implement processors to send notifications through external channels like email, Slack, or MS Teams. + +Notifications can be optionally integrated with the signals (a push mechanism) to ensure users receive them immediately. + +### Upgrade to the latest version of Backstage + +To ensure your version of Backstage has all the latest notifications and signals related functionality, it’s important to upgrade to the latest version. The [Backstage upgrade helper](https://backstage.github.io/upgrade-helper/) is a great tool to help ensure that you’ve made all the necessary changes during the upgrade! + +## About notifications + +Notifications are messages sent to either individual users or groups. +They are not intended for inter-process communication of any kind. + +There are two basic types of notifications: + +- **Broadcast**: Messages sent to all users of Backstage. +- **Entity**: Messages delivered to specific listed entities, such as Users or Groups. + +Example of use-cases: + +- System-wide announcements or alerts +- Notifications for component owners: e.g., build failures, successful deployments, new vulnerabilities +- Notifications for individuals: e.g., updates you have subscribed to, new required training courses +- Notifications pertaining to a particular entity in the catalog: A notification might apply to an entity and the owning team. + +## Configuration + +### Notifications Backend + +The Notifications backend plugin provides an API to create notifications, list notifications per logged-in user, and search based on parameters. + +The plugin uses a relational [database](https://backstage.io/docs/getting-started/config/database) for persistence, no specifics are introduced in this context. + +No additional configuration in the app-config is needed, except for optional additional modules for `processors`. + +### Notifications Frontend + +The recipients of notifications have to be entities in the catalog, e.g. of the User or Group kind. + +Otherwise no specific configuration is needed for the front-end notifications plugin. + +All parametrization is done through component properties, such as the `NotificationsSidebarItem`, which can be used as an active left-side menu item in the front-end. + +![Notifications Page](notificationsPage.png) + +## Use + +New notifications can be sent either by a backend plugin or an external service through the REST API. + +### Backend + +Regardless of technical feasibility, a backend plugin should avoid directly accessing the notifications REST API. +Instead, it should integrate with the `@backstage/plugin-notifications-node` to `send` (create) a new notification. + +The reasons for this approach include the propagation of authorization in the API request and improved maintenance and backward compatibility in the future. + +```ts +import { notificationService } from '@backstage/plugin-notifications-node'; + +export const myPlugin = createBackendPlugin({ + pluginId: 'myPlugin', + register(env) { + env.registerInit({ + deps: { + // ... + notificationService: notificationService, + }, + async init({ config, logger, httpRouter, notificationService }) { + httpRouter.use( + await createRouter({ + // ... + notificationService, + }), + ); + }, + }); + }, +}); +``` + +To emit a new notification: + +```ts +notificationService.send({ + recipients /* of the broadcast or entity type */, + payload /* actual message */, +}); +``` + +Refer the [API documentation](https://github.com/backstage/backstage/blob/master/plugins/notifications-node/api-report.md) for further details. + +### Signals + +The use of signals with notifications is optional but generally enhances user experience and performance. + +When a notification is created, a new signal is emitted to a general-purpose message bus to announce it to subscribed listeners. + +The frontend maintains a persistent connection (web socket) to receive these announcements from the notifications channel. +The specific details of the updated or created notification should be retrieved via a request to the notifications API, except for new notifications, where the payload is included in the signal for performance reasons. + +In a frontend plugin, to subscribe for notifications' signals: + +```ts +import { useSignal } from '@backstage/plugin-signals-react'; + +const { lastSignal } = useSignal('notifications'); + +React.useEffect(() => { + /* ... */ +}, [lastSignal, notificationsApi]); +``` + +### Consuming Notifications + +In a front-end plugin, the simplest way to query a notification is by its ID: + +```ts +import { useApi } from '@backstage/core-plugin-api'; +import { notificationsApiRef } from '@backstage/plugin-notifications'; + +const notificationsApi = useApi(notificationsApiRef); + +notificationsApi.getNotification(yourId); + +// or with connection to signals: +notificationsApi.getNotification(lastSignal.notification_id); +``` + +### External Services + +When the emitter of a notification is a Backstage backend plugin, it is mandatory to use the integration via `@backstage/plugin-notifications-node` as described above. + +If the emitter is a service external to Backstage, an HTTP POST request can be issued directly to the API, assuming that authentication is properly configured. +Refer to the service-to-service auth documentation for more details, focusing on the Static Tokens section for the simplest setup option. + +An example request for creating a broadcast notification might look like: + +```bash +curl -X POST https://[BACKSTAGE_BACKEND]/api/notifications -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_BASE64_SHARED_KEY_TOKEN" -d '{"recipients":{"type":"broadcast"},"payload": {"title": "Title of broadcast message","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}' +``` + +## Additional info + +Up-to-date documentation can be found in the plugins' README files: + +- https://github.com/backstage/backstage/blob/master/plugins/notifications/README.md + +- https://github.com/backstage/backstage/blob/master/plugins/notifications-backend/README.md + +- https://github.com/backstage/backstage/blob/master/plugins/notifications-node/README.md + +- https://github.com/backstage/backstage/blob/master/plugins/signals-react/README.md + +## Processors + +The default backend behavior when emitting a new notification can be tweaked using processors. + +Depending on the needs, a processor can modify the content of a notification or route it to different systems like email, Slack, or other services. + +A good example of how to write a processor is the [Email Processor](https://github.com/backstage/backstage/tree/master/plugins/notifications-backend-module-email). diff --git a/docs/notifications/notificationsPage.png b/docs/notifications/notificationsPage.png new file mode 100644 index 0000000000000000000000000000000000000000..7c96ab77af2d2d9527acefa99027468e4d5b3782 GIT binary patch literal 137787 zcmafaRZtvVxGnB7gJ*D;1Rvbp-3bybxI2Tp4HgK5;O_2D@C0`anm};3K`#F}_deh1 z+7JCz^-Fj4+RJu~x~d#D1_%QV4h~yEURo0l4mA)C4zULf!8c7OFwi~Xcj=e63A&5Cfjb-=CjNg59xgMB zuDmJ*1o+9j%-^;H2EF%si|tsl07HY^dZERMhoC zaERgHsNfW&CA583kGmn`j%zxUyu+(7*yL5th{%4=S@Rh(!f=9bkvNqKMoAe!om4|o zAKC*5#caN#Fc%CmBbj=+Y;Bre>tWO{xx<_^*Nuwi?k3*COD30$OwIIt4DS1L&rt? z{??&Z=`jyFiZm1WH2uM85*H4lc0uMZ+~umOn%bN=crL}9y(_WkN07+aV;Wd%hnxMd zyPIt~n$TT2{PBBlkpy1Qv21cmfFjQ_PgP~aSwu0Lz}nNXW;=QPc4&OxOcS^FxSq>r9#prj^4~@>*y`2 zqvTpX_8gnt0v|Clr>?YK_YsYRRx$RQmmSQK-=-o7ys=_s+*IXa&O$G^A`OvI6vq8h ziB)NL=O;2&e1Lp{%qTgC2~qD7jxA~8w5&m|>{Hp~TI9qO3E$Uqe z=W-MJT5)1R9S{hDeE3`F5bDZvJVns^1y8NvZhD8dXOiZ%?X2zV>^ownBY{VM&&`Yk zw|M7xA7gA6yH0R+;oeB%TnOBE>^=^<#q9gl)f{Ir67P$h;8j2SP4tyqo7bNv7|v!j{5wlkaJGkK$^*n= z$bQw_vdxjZ))UjC8}p#N$ET;8Z@nIK6b>fy=k8Be@Ebl{+^S8asG}u?eXW$x_IVR- zm}lnm?n~O4lI`XS;?@?UPsLMuOZJ~lv!q<*#4jmooJ+<|-Go*>++I^nOUG9g7wT7t zYhp#IM9 zy#0=doq=0pxsxYetm=sD(=)8hGuthK8uy-dfq4q?%IKt6G()_av%g=0YctpgiZCXM z7$ZjpjqaAi$n{GwiRZOk6PGAGdtzWd^Tv$cnDXCbgU7Sc1}=L1-LVsU9=aYmQ%Ri7 zQP*mk0m4DrBp*{}Xb)wulASMbR{e*WT0Jbj1l|tae;3t=Y(F zLOIDJljJuOzeA9$v=~7;kXkyNXM7@<(6`Zs;oKA`y+J21Vaj3ZP+Z8S3f@Tgx1)u! zQ&;PmvH%QsC$HjBubtwK-Q<=~ka`tS zs&CARPY=V2&XmOt*haZ(QA+g~;zQn=g%TS1dLZjjd~Ch7yz?&Z+qq8wSK1SE=Uiv;e;FH$w;D zKe?m0obmQ&tKm-%pI4dXqYdmE=fY)WQEK8I5I&aJ_WKBHB1?^vF9CP2@H?OjRj>T6 zJwK$M5=d$jwSoBV`*$6HGUwC-*f7eMdB0m0_@|jLe{A++gFD}@n=5?g&E_V!2~$=( zs_CiLo2kHo;YritTO~GG5)^gPao?xt7|$9W2e4SiJo@`%hH;#{ za@E!?Jw74JljZOi8y6(Z?(>Rpitp5I*tYQp+q{&$NaiesWC?zNx6JQE+mrjpeBw#CqVVVweut#yRLv?B}=6G?#HrX2_he7;-{`C<5eeY1A5c zCG!UI|H2Ov;pPH6t?J_hPW-6ip+Mp1;7>l2SPZU24ZEeJ@dO}04 z4-4SPqc?Z>1fkL8zFpW5#>K*zB&q%qaB)0vVV(g!KP#Uh z6jM*vWfyAS_OOng)hRq5XwMSQY7fX-EDh0T>le1YpjNY-a)kunvo^q0Qfa4MP=5Eh zzUkSBa_V2+VDEfY#gUSFhdI6DL=k=Xv5$-@w5+yJs zEQK1wOfr_Z&^0msDI|W%w~OfttBha}h`v~gcBF+w2H+)Syq7qL(r)lA2lSGoyEo58 z-r&qsOO;6F-iqwWrmaVBJcLw}MzLC?1X z4_lLpZTMu_NfLrV&J`#uz9z0D$(94?6}N?xlu0v7ATG}sA33gsRGOy`y|_F65&Ee5 z`rI>RUSWJC%omoP6hpWEhE1L4QF$B?%S-<&e|ak9BiykM1pne4WD?i~cH=P+GDb?l zu(e3e$k!g*cc0m6GhwnqwK(Ad^6JXo(Da)WKW^AI?R} z;}V-h@KE%hf%t$1!14-Oo(3D@apHJ04sX+vHL?-Cv3BBf#L38}KLy)w{Ufvlf>8FD zPxN(|3K%rzX9249js~*Sq-Tug5m#g%ehi4wTbe91L39UKa*%JkkFF$Xe8kZ9#{`E@~{AQ2TlD!jgbvQne++DUQx zq9l?z&sXlmsBM?aMB5NI9LHDmmY@mZo#*(0r>-JKBb?w{C{r+GrYG}RcR%s0)I1L{ ztSz!B!g@&L-`y{s0!s^0LbI;$%=MUbBZ!*kZnWK55jfZZsSI%S;)B2Uj&J_CYzQ?& z3YG~giiz?FFK*6d*qg{fC7>a%*Q;IXsN;GxM!;G^R7GFiH;$jW)-AGvsw5*)PR1*Ypg_*8X|xUdT`W zCn@blknfT;12KgR;ll74x~Lz<{l`sF!7=(>I>18Sy(F-z!UW(!v${KMCrniUwk#31 z5`Ej`OQI=84DMQ3o0|TU=DBgfQxTe)OFe;Z(!RCS28(l-0ii|W|C+xhKinH7% zE_AkFzUjS;VfIP3{^e+?moCN>@JIS(gaGzMF*Tv_-_-&-wlZ0N!?^F1Ex)qOJQ4uJW`M7n#CF+Utyq;)q0yl`j;2ll?V&cS z-%Y>D!IY2Au>dONtjYvl*RIetjQWD-TBh4UW_|)I|0ZPPvtCZlaSSCqAQsU4yCl@) zp+_S{wEE;dFuq_njrhYoL>3L!0RP3UOTr1Tw+BB2jd3tQd(;KXtFTzv^}@n1F;xc1K3dZpP0k@H)oB2e4r3;@ z@Mo!|asxRf?uC-hE(WsxCcXTo!(4<8$)6aHo%y=t;o5jqLKc>Ub49|%(JHB-Xu%8L zBdu_IwVLg}jg05h6AQY(l%A!Qk$T|P9Z4W|3K$X4u)C<)_v}yj@7Gha^9V8x3HD&^%smHZY;dRz z9{Ub;GH4hj6R7x|+ge0&LN_!=L@&ePFF)RQKo`NNJ+0geZ^$$+CcncW{ICs*D$U!5#kMUYq(n(8EVmDh9g_eLT!J6g#w zvA*gTIzd-qbZK$|m?$R-*3G?pNr*kqHSvZmwG0vHAmKGC)$eY#@ZIOYS@!K@xusd^KhZG zpaD(L%+C=`($TgM0m|IHwX+46(#m4tiQPjalpeNWRO!__o> ztsN>JEH5RDo$nSgz}2~z0M3XQwmt6#yc}ZWJndjIR~rz|91&s=(J0P=(%HC}qT)@d zTvybs{~=#xbt}vxzV9r82C?s`P*OhUsnZh)LnLgs8am&VeKG9K0y>=jDMoSg>S7~l zhk|TXH2CXoIVD5L7Qi0Mab)H~XQm3it_zL`kF3R`c(k8lzydapi1skQ+g!BSXvgMl zS;Qs{t{ilbP)BpX#KR)y%ezPnc`j{Brs+rEpuiw+5lC%y@O=FO_k6n0zU}fJgU$Hk zpX0!ocjo4Mg5S^_W2El@jZKWJOONs3RbudPIH+GLzoj<34d&#a8vkV_x^?iY`p#48 z-0i~dl{rDnodm2R+Ejt?v}WJW1kFP>C-TRtt?lPH?`d_rAArQU;8-xN&xqbM&;ilCT^nF$r}62 zx^J{;grV4W?yW@QX;juwk(e++0VS?Q4kUR7={#nW{XE391NFO#>~5r=- zXP^yCCj`Bl)oUsHqdlbqWwFdIX5f)U5GbM{5@IL3un*M!3ZqJdi=!Sxxn!&O2+1VX zq%DkE%Oybiz*_p3<(Fv5SVfs3w=ua=LJ51H8w-}w++e;TCJ@pITOkj{T+*u(lnl)gy?pcHl-u&Lr)kfRoqu8W93i{03ssViQ+Agx(zZ>;5LcvM zDX-0lzNOpoZbvCgLIGrMt@dgmPQU?i!^OY*ba5)JWXe8$7M!tG$)-nqx7ryEPg5tx zQ?Oyl?9LrJf$l0&K)qP_aeE#bB8PqZtxVjP@By&s>Zcr1(s?_7!jHn~9l~+0i z&0ob&rV^WVI50{>T1bpq40V*laN(BlMR(?wJfEJ7x}5K{KmOCn^lkNTc0+H=s(m`1 zmJ+LFMFx^+y@qf36)12uW4{DBs&2-40_7ZkEWX%-8Y4xVGip|cNubG8#mxyly*fv{ z1Tnu2Rzpu7>{4WtC+HRFRevG6OeiKuX9IE&IE8D8W0LBhY@qi#-z59QJ7VqiX|u8h zP8uCkGNCxHr*)EgQoN-SQy{C@A2!X6oue6R{)3jm_w+(}X`|f*9QGM!(gkL5hDfIL z)zkPfW>*BqN7bOPU$ zXh|y}fy}F;ykm ziUn}KYWSH1kY6D{%ljn-)awC|_K=jTZoLTkO6^BmH2GVbtkbvaMWEE>wO^0AuPe-U%yUa)`iC4H(ErzMd_rAG z*g=?@>BmoTdGgdb@n1wqQb(1B*O(jzp&<0r0I9X5G~Q(k5kGPuN6Zwa z0XP>QN7KY_pP5&ez7q%blrhuY$g0siKg}1P*ke;Rqisj7I#F8you8y#YpO|mJqDGF z(y|v%hq9)=DvXu@gYCkT_nk|LrVqO8sc@yh?}ltri}zsBs7Nt`X+iQ~PI#QU&*Qo29X!SBkxyc6iy^pPs%ZR|AVu-TKlT~82c9qxSi zLCxFtEkKk^e86z-zM3?mh~eHo9t34c%agy$FPTuTjTv?>0XTAtTOMciNO`U*oG^+B`SxIKurz#zt;B1zag$b*vHz(*%UU5{T@*7&i?p)&O&}{|nyInD@yiz1*a<9eVPD3Ar=LZyU2L6i;Vuj0A+Hlx;)&=hp`*zV1oTIK zhUl*8S^YrU`Cj#zoo>_mMHoiaDZR$`VVXXvXLX-vl#?^ZXrP9$xCT2gBI8SRFDC_b zv8|DURXXBn{D%3*P3hvBrNZd)FpLo?(JIwok!eqNxZ0y?^nQu)-PEsr1&Tc$=!&Z2 z<{~^MU5Ys$LnKZK^?ROoj8GZt)3z3N-_;&nYDj(yyERENta3Xiyk#KQUR+aht#ySm z!WNdYxXc5SQMqa$IOkcml_kSBBaJeAF|twk3M)AIIAYZpX_-1xlbnaG!;XQiSO0>Z zacjYO42!gdq-aKa?f6fYX{}xPzNTv0TYb3bFtjYDso0(3f1%}4 zTDs3}=J$kd5^bB>Q+zQmES=I?gptX$#G_|sYmiD2vYO%dch6axRKw|(!d2dQ_56(N z;Og0ZBqxoZwq^{caqnwd>*5H3urgxzu~qw>C*y`4z2boV)L9st1Rs+n0Te7=4wfOf|Dk zC(Ol>*Iy<|h@#1`)5U}4Jt5KA8Sv-r-J*r(75d$=mn zA#862-`tL_=k^~-ffTjB5HJo^D#_}0ZU>$V?`&sEmk~|Pe+-#lKx_{j5SLeykL5OF z>ijO8OoP4RJ!fuAB(|chQG<9V9nBP$TRlI>QFma6Vz+R@0;gS{4Q?uE);-c0_>~Ttt z-T~|ZpTU8yzyjsOE4#rgGlCAVdbVRaiE|nPZy1^my+XYV8`{74?wqx{_W{wKR&wNu zyRGSNL=KVVUBk8g=bx6_pVhxa&D>8=m6dvjW#Dx|#5QmvgFn!_A_xerV(M3zt>?3L z_sZ5pUN;xNUO#jMWez@{eddqf`!QL2BuWHD%RjN36S{q#bPP6q9fF*X5s%H>d$x5a zg8oZe1H6p>v(e#i*yYCi{y;9ZYDSlW?y zQXr_!TxNlXkuJlylF5_TB$$9j-P%J6=%NQQkA81LXTz2Tcjn-J!2gf_!g(`bn}qh> zf5PC82rtq;TkY1~toqba8%kN@IjGv&;#nj79@$i?B|aJo=vUE+%CS{l4$L@?{F-z) zU!e=c#1Boi#bMx49FW9l&b0pR!#FWZGg$jQ`UXK|W)vW@wONDBz+4foaMzmT{Ew%spuqNip zIMJvVi)w)}7mt%fWCJIJHh)qsMT_hnL0F*T;)LpF%mqz5;B5I`5gP`)QCmYOsk3m1 zT#iu09Hvy+Ney*u+pwLnykaCzT4bdLn$*XFFxvOpLF!K^*sDyShCHyWAA<7r zVCL2;vnQFsmR=@g+$m#UQujc{_(#F43$ooYEP8LqEb8E9$M@FT#l+KKm4Sy-;SnY(ipHVJ3&uQ5N9Qn)M?!Z zzX;nz{{$LT(8|Vn$%!Nu);Mzk)?-lAoNB*EQqil{Hq+c(ApfMUs=lB|E;ck#wqKvS zOnVFTuOwc47ST*Qzmc*IGNBKaC3R8R_mbS=2w30$!U`pw)Gkb&Z z&NEb|24ft=el6^F>6iMzTwIM5RVA5~&{z}6JUVpTq1Brv?} z_~5silyARqM}*e6ed}p6+oPEGyU>|swLO9H$w3a}Mm0EGk^0E*xj{WvPLa_V!Rqoug%CSe3 z*LzICM^^inBfMpO3p-L~7{dan_!zM`12l|imn&;KEP7`TTb+N1g9%@YU{=}I% zDnmG{a3lH#RYW)b}$BDzjPoi zhK$iaBAT?PA2GIKw~MzCu|Fp)z#PEk5F|jF^sa5w>FDeJU{Y>QOYM8=JsX@7z!J$w zX-QzMOue8!6y!)9K^Chj9_VI0SD_xK7p-x~e|gRO(m=eF#4$VByxLXWOU|+Hydf*6 zzj$A{LQMuYc?!4QE%la_u7G-XA4vg|#_PDqCDf5$X-znbFTTUFGVDA^@G`?(D8Yf* z{%`zu|KcG)y!<4pZ}9p~W*7Q96aySc41Wy3DYzhYJP7x=*uGYj3a`iqR;~j-mr$;> z%~S6Ye_;to(HNpi6*$(_i4N{HS9{2armFVnJ6yZX#2TOjg$r$x&bL57WG7k6*` zvTmTV^Smi0`?LgrN!h?o-+Yzj;vA9I6~NOlyWY_Ir z+&^_$_{nNddqk@`Kc!6b4~3W1mXx!A6=_+(S|6uoNR)|lM5I5-a;K*fX;toWah`U4 zaqY7Af3dAVK?aJ@R$axoV8D$l1TXgk7qYk<7xOgBXxYkd*(xe-N9LpLy4_W zkTx8fNJ9?pDjnW10TmH>z1+&SiDJr6_I9(%NmJDAkM`?}(aH$iO@n^M)5 zpE^_ijEeqJ-6L{?mef~01(Y7gBNQg>^VF^Fonb#}5V(0F#!_wk$1h5g+r<=nB@3lY zoJzxFZAoSQPQDOzRI8@@fM(L?Pb$HL1mYMzO`uRyz+7gx0jp6Hpx@z@ph9RH0_fTz zj+~y^0|QTt&rWCq{=vy_R%MUMdr&cLf85R`wRs8+0RV4*L#;z^n39FlDUAmvtkt#- z@$E?#GiJS(o?s-Du0_rzGqS}$=^3mBI+15E*lkx-4fBw8c8@OH=C zO8ywTNP?+Fq7p}&z`(qd@AZ%feknMM1M1v-YjZgDMOf8^{hGHyl2h4=Kqz_ERkd^x z@dRZnl+^#_P*wzSdr#f^i}Z`Eycue+-Aj&LwOB=wxgA7Ba}EHs(PE&Z4N--P(YCFH z`WDAHI_$gVCPhrAk9MGF2)+c$#`DDMQJp!EYgIbNRaQGak#G}STG_ZP6N$f9aLIay z-B!{j4N@3J#%&OM&`B{2>!6@o+Dg0o=a00^)mYz~mRniv+Uy!#i298P9L!6pNXs=g z$vTwy5l-6t_P03LPhPel)3wlMoRq`vX)zwPa8W=5;*xP9sC}#ZolmXnODq{-HU!<_5&_SdN%>|a9fN# z@kZmE5eTkjQ6{c?hF4W2i5sZ0*o%3kFP^DoYaC=KT96{0FCZ2d{0rn(zEDEX-c3Md z^ARPq6}w^PJ?Coy`2g}$)aIMLX^JV^QUryXKz)u^T+vna$paRc?;@c z?(!c9tw30Uk;-m5RXKLKheNY=R}+~)XX{r7apPlZNx#fyW)1#WK@Vm%*A%&V2|jb) z0)OFXi-N!k+q=BFPhFJHKdxLZ{t7zGFXQ%8*u2R(YWeotbGp@ZVna@?DRctcpNG+IF zP#0=Xj$mtKcPj{k&LzuoNhyBQOxp#%Gf(fCw6_dmcj#4lC6lb)ksF<~a&D)PIWPSN z2UvIjkS^{;c|A)Tey3a*8%kQhuky{`^W09f|3X{J;SZ@)tNNsm-7JFLT=8YKCnV^k z`J^OQ2e3wgIMQRY8T}{{b;|>uka9H5r4CLM8p9^mtY!qyh7FqjTf8NVfiQ}eA{GRE zmt~Iz9(TbPTDeg1%_!x=4G5!;pFQf>1Q_ z)gzqaBAD963?!nczi{+V&&j}N+8}|yr8x|;GsiRI(K`+){cSu8*;?4~)v3TU+#-JM za6@sq{wULPcn@t$jC6Bqaw<9)2AM{=Re<4rFAo5;_LWN^8q zZijCNnwbrhQv9636f$p8&}^twIQ~#KU(dn$JDP+SM4?E#D222JswbLdpN!hp1lOkJ zDAF#lGB<9x>tQdRJlNLmn{c2-$vh3m``D3`DZo*R@2;x0Z%Fq zx}ggtR#zB7I}#mqmVVYxO`to>H}Oj9A)yb)&kP5JHl=5h!<%_xxNJWfN|5}EnEgPX zU&?%{S#>`@b9-~(Udf+r|0Jn0k-!AX#$wgR&i|M}=>qJ{X>nfWx8#-_jNbfe zi-bQ*fY(p@4s6iNM%v$Zy8KRU&HF=F#f7ru+L96bkSv#M^rpc8?;?0V@awv4lkRT1 zLqTuM*w5LvmL`h#6Lw=ZR?9)sUQR4Mx5A10>H=b}MG-AUIwvOdIUiRo$D2Kx!@US| z3n}<`@+Ai5=V+R2x$SK$o>#2C1BrK{Z-+;n z3qL4Mc$W057fr)SPNG-l;v?G_bzmVp>fa;3AVa^1ullxF`TWd!<@l+miRw>R?s~*Y zvoe9{ZXv6}%9_!pUL`ijutYDX`>2FV5}uXO!)?i=KRW$@{9`K2=r!oCQ-Im` zC`>qTT4ZN7CBx3kC*dWGzsMngMG_tA{0kg7jw(2l$1sHN+%ABgn+J3&3QaDWdY^1@ zGaP)_&Hv@vVxV5>Bw4D+=$Qb_!tQ9gQQIe?oFws(qQmLyG{D#Rk}K( zc@F+Bu3aV_KN^eROg$1NSjJ2ZiB=*HKJ|T;w>=|hD#*__n6Y=yob;0>Lc1QlArrJp zyZje1%~f<6sTn!#pgWBDY9ZAT2_0Z*Xa0-zJlR-&{|a6(;#1=1(kQ>*kX{lC=85CK z6zD~o;YmxF3MC~9|D=3u=C!LKd8s0$1XeFxwqfzS4mGYU%;$`FLutbm6#~mkfL#q@ zb{W{PVWtw`(vMb~xKKI@dMq_Nd=VCcu7$xjbb##dt(o2ZVmrh|au)wJ6@@EF0 zQbyS~sF26*xb{TJOIQNv*)%1rdEm0z^BFOOyVR*5!LH(C+V&7FNkLXi?KiYjS(qX^ zwzU)UbbPU@Y&@bJOgF+kY9?4-;TXUD$e5vq%d02ft@PesLIqt}>S;Ce_-pt3raoQT zB9ixYg`8@naCkB8W@XQ;<@;+IaUA9CS^RNU4mbDST&gsc;u7%Yv9}Jw33&IG1Sn}g zA}Z)VircsyUTN}v+&kM?i{Qz2>^6+))Pu4))hQ5M4TI1mL?bjaXAQzH zo>$xjmpE}uLO-?amy|SQ{dO@E)rXprk44wML*O2O3yIIv|57k>?5`!jLqc_WT`Be06vE-YeNob6weW$fU{{wcjXi9q_1UQjLL z7_eErnYuc4I34;;kch59+loJyj`un2V(i@iC z@8AGAwW|!Wj&+=8CL*FVM-m$9r$<>~e%%!(1ll+Ac+1(7(0L0TQ~9id>LdX>7G@zMpRp7%MdNKzfD@6g1@TK0MdN_l`^Zn2q3P zJy)}_)-`e;-=&~erV38!zOSSfiV6+L*?9PvKr(l!i^TIod4e>}@MEW$!>4iV#XAL| zPxhya(Y=uxF`Nhlc0e~!*d+M3jK!$>t(-0H=NbO|;i~;C=VsR|F>6a4t&El;uWE*8 zI&*5@zq=4r(lMmJeDEO0Gd5WwS~32Sn8*M&VM)?d<9|$>B0VuIA<`7HG!ryB?nXJUm+^WU7H$l^_@aEbL8{Na0?x`gdn9O~ zKLglK8R3;Xho_{l>%>>_(Fp+d2w{I`eFF+vSsTO=Apr>Imm`?#ol2M?GO`vnZqMYv z|J=;}Fqx;n08fQM8Z$~_S#_V2f>n+{hUS5w<7o_jnsLclGeCid_>o-d{L=y$HJ#ue z0yO8tki*g=z))2rL?x2N^}=71-P03AfQZ(QBaaQ#d{QF@!Kvxq1~1<72sTkkCpUr8 ze|I4M^xV3&0elVM`5{q=a|w_^XJNx+j*WSV#5(+%hu@xI8f44z2XUoZw$R{1qFdtf zc7j6!i`JUn%zZPsiBn^=lYO-Zr=Vc>Q@V&pyY|_FUuoChPh;|!2bp0MH@><*^Op?# z62Hj-_DLwp7)4nEQ3aQ7RZgT1Z88pH@5~Rcz=gvU9{_@}BdX?E`qnH(x5}DPW zPs9ioj+>89MbyW*6(=88w`uu;rvdR?z>->T^N4-0r|=M(yV{x_O(6QHiun>+(dus? zb0pt1e=XphrB;JA8IT!Gu026vF49taqC484QvCCY)sb_NcARv)t-Y5da#TDseBo@_ zMiti&ai}Go%QyI@+TzFp!}%C;0*h{A!&kpM-4(l6C$vbyA7j2QnBbvb2eDl10m)(EW zYjWtH@y8|Me~k2gYv{0Z?r_B%Cu))!7B@DDO65gJw*0QLebudf{W6R zPCNlei&KVcd$WZ{9lPKH1a^Yj_vht$us5n3z{Gm_YubjP_S}$c!u2<2Tk>i<&JJIg z3&DI$MANv~dv!PIc0Hfs<467I`-lOmKzhl*Q-a))?@bAxMqbje$(5xRO%weX1+B=9 zhDBu(lO>)&+L<{eIAHB#96TTy^aK`uKcPq&50XzUGB1gjb=CdFX8)=pE!Wp4ArPd5 zx!4-@q*A@Uw@)-y2DI{vqgLdh{#-UQjJXR!;P2+|8+dcfzrU@k^eE66)6Niz%v%dx zl67?yh%_xx&3;_0gC^wxQbTYw{pHMeQCxna4GhrFKX0z>1~|G z!MsV;C-Qp=f-M*S$}T>RDCusi*<9J-l+zWdkLF{r)FDH}^r;aNmk^MH}4ym3+yq8}UGqpzSuyjAFSQ*Cw_%8!oz^IsL z(l&9H`}=&v_1KaY>QoH^UqGhbHxJW`XgWL;VZ%lkvpVZN+5}zZMoKG_?q<6SHl~Sp zA&gu;jAysjn4B0zgZU@}h|IeaJQQ)$pPVOiBcHX}k2Ok{bIU9YdPj*SMl}wP(zSV92~qO3MQ2IQI@rjm0$I00 zsv1LT|NLC4L-z;zX0>clau~kL{AC++rVXTu=&wyOmU z_+RI139+N+^}?HVG0C_PNbkAxJ{Q1JtZ3IDR@MyjRss?{49Zk&0Cg_>Ay#>vwNvjfE)-1Vr#>8AB2F(f*nBx9J;?X#P93B;EilQJI+C_aB}A_t??m zjj}7PQx$uhOK3tazSi12#9PqXjIVCR#pAg7fi}{*6u0oC(tZ>{>bO~%+A9j8(*{v# z3ixv+1o}_{pW z#GgHCWQYaN=JfPdg^|)e@n{bJoEc-X>u8rhgh%0$M9J%5jj0aet8|36#TD-q&y*r)$>gRtThcg2|6X+$`wRkTw=~P9TPK?&4Gh75LW!*Lfc(S}oQG2pN*NYEUMqS?ew52X9<;LCYnkzC*XK`4J!HG|c zD5CeLDr=wWkw*6xqz0e=S58t8?A(zD=4s&>_SlBk7MSUTmpGSNeG>xMLtAookeQ;3 zV-dax(tR{AYdDD>ehOAVlAQteZ2MRX=83Qh5mUvh%VMLrPSIrILeJB(Ln780#(1Y& z0P-@LTa)u7_>y#z*XEVzYc_=vxIet-FN=*O6Z|!-5%}AKU0!~6oY?3km0FCj2^cSX zj`#UY6Hz*|iYbA)0-*L|5@00dOB}a>?Yc<7is)pa+JO+7!+xH?C848DX#L7EWMp zmHeSS-o$%zdA67AV6n0ZnzRAmp9?i6@L`GL5n9O3Wd-1l&cZ2!eivjnF*#UfnMj_MDWc>({8+p^Sq-2BijN0!iF1%u-xp!HEZeA zpNkaXBY6~5u2V8#c~)ziBX@H0)6*awPo|K9o!3R9^f+jia?vMD=y!^ru}wH%%&o!N znxhBdEg8Jywb;q9 zFM!L)ujRu{3i*~H>^gj2Hc)AmBCg*tD*rpU$+D|HFwaIz_5r=%-26x$F}~jFWoy%uiBQ z##fueQ~obcKZ3tl3(+rn&VOO)_@oxjM9*_!2Q?i*RIi%(`hNiDKp4M6OdW2{D2Z6i zX~ec2Tl+lMeL?tg>L9-ElGNF0t;;Ocd9Nn1iOgLSK&BmKQ{MhOZN;;$1RatNNO}q$}+|PyC9m=T#XRH)q3*^&kYjraER?@4<@LM zRCkIsWo*re+7fPiLvNFOj2toYMA{_Kq>ykRQ+VqJ33+=h^oL;VA97ZJ?_{ zl7`kox*-4nAOJ~3K~yk}n0XS2S;}Z`fTQngAm18OA` z@jg7_w-@zmNuO96*S*XEuEwui|By$RJ}`v&ebe~O<@YkreK^E#oG(9^#&5vP+@tX> zHOIRUzX4OjXhwebg9U!;SI=??-=oIw@j71cS%LUDwV5HeE&CMdiriD22m zO)Ao&qwpAX3ilT_+RmgN>g8@tO)D{JXv$C*V!J(YmGNN8?&KE!7f?7aC>)d1xdo6% z;JE8A`@NBdGUOdAQA^P%HGN$wG;u$>UEspCHLOktR-kGTFO{~CS3IB`mEBUrFHl@a zA&)9H823hVX(KcUDQPz#MvR&ra#9m0D)wf^+e3KmquEQjjaX|{ijH(%c(pXztU~js z5m{oyXu7cGG}34qf^MTzav;-8#^uE(@TTim_X3PlYQF0zDBz~e-SmiukD*{JdqlP-G$4Ipo%rMeQSR^t@Dkd zZN=Vit1+w8r7Xm6b{%WlhR})lm4(R!1v%G_)C-orgPjn+)Fvt=va^jRZEas!=q^S0 z+eq6NbVRW_E{-Hdg!rwgw-rB25p}+y?Q2l^7NLcyF%n3`FAhfh2$5!}9{)s$Fs>nM zNdpiCjhK`ycn5U_E6MIP-c*QRrva0|(ZEZ_>n@{}hP32}z=jctYnMh04f*&JEkBDs z;uj2r6e7U-6kvU_eU7q2|F((dHeo&53$;;o_XQY8qjYH(7O&3YBSzD44Ape*n!l9* z=iX$zxlbaE&tgh$GGuiOM4)0xk>$=$KzS(*OgD^TTo-UPP8EhbgUWj8yvYKpLv#_hAVO`w_drC;f^pBmGBw;rJ`AzRXQmOqRbg90m@@mqKi{$|jG+Uy^Hxz9Gz{jd zdVb`6w$B5`h)ItjBcmZ+ja#_hYQL-Ag~qR?Ii7y5h(QwKhK2ZhY7JlO4~ggh6)JPY zR^wOmv-0_u{9GfV>o^E2|LQQdL4bTWB!eWg#^lc(#tcoug{W>gBmy{p3E)#N6Wsn3 zNBxS%c50a>LMbTEULO&^$Ln~(>qz6*p_Fkt(z`l$2^J^F`w_6d#xL^D+N73mmhqE1 zJ7oOvLP4aQLx5RSC5O;bKB#6c^h8d+rU{j0Sq2DGvrfL7O|@)k$VUFQcf2#!D8DZB z{Zvu7k)=79MBEq}GKD()OXAWK?mgPRZ6+qoh_Q$Md7uA^{gcgfkZTx8#|M;m*VcNx z^5_X%dujz2udiLE27TT-wSBF5EJowNB5hyYKKR^lPw-eHfyB{ryz? zt)TIY7a_SWXkbsYb-WbqE46)n#IGnkm)t%wshoSzzF<>kYY4=dPF0^T3aIl_n#!J^ zC5M57Y5Ruu6x%|dwx77asu&um|0qBK;;=*-i{uwMBm!HN&auu<+>mL|LLUEXh+iTD zp_Pv(eNB2zo712WG~&PMzoJepZ&tm$hR;Dy^rs6)&V8c#2HI-d8ik{i^E0aI-kmM_ zw`}5~*da7Ep(z|`8ow0eCz2YEXe0Qhf@Xw3jSx>3BF>sv4#hRk)4QF z<@{7>OfS*+wM18qf$|W&Q&|WT`7p$81mb-~V49k$;y^hBmAD;yg4?L!X*1s!9^S5ccC-&2U?cO068ZgPw5anO*kB;&_ zNN7yOqnPL{K?L~y4;T22Upn&{-S*M=6+a&lzsKu%J)rBWFTJDbpfV9XnGIhI4LnV| zFU<5A9nw@I<+`a8LD2@ND#( zk{YR8YgXMarJXNSHK>&d4KyiDZC^HTw5c_@D$Oc_`M(!p3HRW=o%z%>2ZGg);XmqN0oUpMNy=^u{Dq+;@Q$jqp~~N@3cK({Jc_s_x;uOwd{u&2g(%` zo5J%R3<1)<6FG?c1j4!TYh-KtPKhDH5TQtc#%*@~RJ-rR4~1d|6NFmR-0`$FiQ z-a*j@R}ez7nSiKn4ABbdRXl1*iIA-lHM5oI+bUZRWoz9TP$VPX zX*BOiXC0&BBcMrW2J2EN61hK*P^BSDI)WRyMl*}gw+#fszDYe_Wxo*V$fGI2zC*&T zPGDOk27t|7VucB@-p2FpAP_^+-!eN_ih)qqsNeZoE3*bJBAD8Pr9j2BK!#>~wT?iK zv!>@oU2Bk-{iwc&pPxudDCruH6lgcXq+z{l6wuNj60z9)JjXrWIH9V|Y}n}%Ak9kM zv_(Q=mG6^b)L17LpR#jH5Fb{*_>ki@4n&;`@gxjcbj;u!-wTjq6z7J(l6%uQY2c1HY5bi~@p@LThYNnInXT zxXh1a=B2W!B8NphA5q2I%wF&AMZ`t3M!0UT&H2#QH|dD@<&E*Rf1*kgyS+D!p$Za# zC|9_p4C8Ug91?wwLOmZy2e=_ohB?4Ou#;k^L&gj4U+YFjG8i!yX|i+8@r4@LL;x2r z1AO`wf?KarvQZCP>9`Ic+7a=4yp9*V9yNZUp&|^aay=?zIt;=$qrnCi^|7Y$+d;jX zO?)2Y+FLW%MkclMco2!ig$Um)^w?j2L<^|2At-F@KZRY0D_^_Q2-L8z^Bf0+C%)(c zoV&8p3n0ey#5N+MJ?d*KE@1>ntv~8P!;sz4&KUwIMx>ia(V`)aD9;d(9G~J+AKzbX z-zA3{Posw?z{@?_CPf@7F27*|7^OIx4c8C_%nP-Bb5q!AUQ&909SE^qDAxg6;*Rt7 zz~nFlBny|+wa)sqee-rN?kFx~Q6W()nwOGtpuE3bK;!O8BT(*Orw#WK`|P28FW*?h zwWro_`R2-un_5lggtjjPRHF`Zac^zkG}W`gSfMfmP>eQyVA{TQ0&^}D@W#3TDOYBP zK@QSa>p;I>+P?MrcIDIZ9h3s4{ys@OZM@ramSWp*h<3VMTCqZfN}N*&Tv=cV_hO z-iS9Vp`X$mv?y^DjbD#ibcn+Z)I^NM&xnUdJX`q`TjRI>Ij8ZMh({xhM?>ROqh9US z_%$_70S=`Fo70pI82=U_p7%rRk*#ZUqIk7}l0)lJ+5#`=?a;kwYUR)jZyS z;rSIIU9WN_LR~@K?6|m~b9iupQ_DSl_{9UCg?$PjYHIx*grKur| zGSth82HSECW#wEvcH|T7I#g#QYDV+Yq(l=Mvg->2oWHVC5x-rK@Py`IsD){2;jxZJ zmKZ@~T9?)Vm1z!o^FyM;og)NcK_}j)ts|Wh2+N*?Hb#hF ztPuoWrfeQ(rSPgD`ZcZKv7@)-wAGd%e!0dkWHrGL-KY?0smb;1CD4k{95fOI61f#p z^JX-AGf3=?j$@99h^S*VP2W&65%cj4Wwd?CIXD&Y5pIgcFCCzBPDAMKqwTBOBd5`% zs_uA9Q&#z6dz{SDM3Jy6>twV)hmg3I^o)nJb_ zX2UqC)Edep5ZEnp&xq4EM!e4<<;wY@l!Ugg$IMU^JJaRgq_(g0N0uhDVDv~j*d|Qb zBpYSKd8)GK4l_a7u=s`)Mh&tNl9)ggx8qH@IFhvWEhKmhja3j@z!^t7A=Ng5XuxV< z+U$^e8=-k85qoSMH2Y9O^%-)}lzbtBs#qZAh@60ef@6VGM<|6B(d_fzk4=o#`JUSw z>HiYizSa3wt{YPRz0$bnY0i#~CcHrl6{M8hKl8e5_XC2VIjA6zD51?M?Z`0HL{-BM z1w5>`2=`JX_W`T*j3}5T#=E9{UFLaiG&#XW{*uG+hVuMP`gyF;T$JZ3 z&P)NVUqnOGQI%ed!hWe?t(-rk9RVhVqDi8VVjqAZCJ_vcM~f9rvmpzRj3BimK}Yf^|(v&G8ZxTAOvP1CO%n`NHJ^KK)8DP`|ze zlzD!_7N~SY{2s641+OEGU+RPIyPAW0>}pp#tQ+xaA*k{NQ8)39c|^fd2$=r$PT`dj z2<$^6_mYS>JJQFr#&1J)w6G&7qj?Dnb-kcR!_#w|OA6asV8Rk47p|}2@wZ+u6Nfnj zpGe%JuX(8p~r#qayrD1yDDRMQ=U zg;NXf#&vTBu@-%!2`&rS3$%T$?QN}R^R*N9fg*n^6OsM%x4*WpIP z4*aTxYa>P5a!1_7#;Vg}K0d!c{VC2dFQ9PpvNdvJGf6ePw;Y7WMX4XrkzQ@2@i zfMty)Q^6JNMhy!dmvt|^{(Y3 z5D+MVXhV$8Phch5Rn1MvA%cy3%`n7_8iADD(>Chz=f-8Sf9haG*TPjr-Fd+H7?1` z$f(qQ$Pg8xrJidJP95Ha<^ta$VQTGMw=tj?2vbrJOr#f{yR=VvCw^szX8T0DL}X@f z5DCq%XulLqlg-yYZS0+f zj`(dFj{-!gu3-muftcpT2c+D3qvUvJDE3=afqw#P5Wfv$L#-VKnRv$;Z;tp%`6{U~ z<}3%wN+%>5y|~$=10#K1>e#9g#^{t2nuFXfU43E=H=a9%%MY&_1Q>XQBdMV*w0U8P zwl9c(PdZh$%k)wxWRUQvQZ1w}Z#*K8y4uk8)fojeq_3{+ODtZt3g%K%lPF;5QS3&s z#-FUl2huew18rY9Z*rg8V&uXNYQJ6z`EvJ~ zCN5bLD{TN>he@!NiYcHdjd&GwUbjzUV^@RJliSQ=Jb+sB5j7+@*NP;G zSgbXfD~;bmwN@q6nx=(m+=9}8>cump#et5NA_+gWI$^c^Gn&`mbS!Kk$EDGVWsPgt z+UZoh?KH%sS&0nDR?|2ZASiXtcT_c%GYGPXVFXfIkalDBbRO~=l6UK|My$7uU8(U2 z5R{}Kf2|ljLi|pjlkD@X{t$F&4T+#@7&bEV0U`}##_Lw+wI^9K9{@Fb)HBXOamk!w+fi~DHnekkV=v_S zUc~EUX#dJ{mBy?=WzM5i`B$%gLA54(^mkK!Q2U>vA%5{8gipOv;M1>=%J?wfxdyg= z2TddVsPTKeju$+5#4mLsW<97s^=YhTwDw?+4&7c2!W05b9Q<(~q$t6n!l?eo3lODX zB?90u2w#u01``@4!XxvJX!I!4_SF{c1q?45uZ)&&f+{E~BpEMu{kd~+_30Cz8q-6t zQ|^6Q>aGM8@4{_kA>LB+LzJR6Q4yu$XN!W@3WUpu&>Xr~;P>xz(Z;V=w_;rzFULh|`xJ0eeLdrp@ z94?9vvNYV(VgD(I*w&~ct;Aeryyd(c20Ab4ilPWql6e;b%_Z+EZ&7 zRyHct9}iz!-bA{hPE9MB1NPPS#ctH8Qm9lI0z#^O zL&PuBLhM7l>Hao@AR~;|UltjLdq21J2(?2TDZst+6M`XH+l+TC9hcV?U5a@25WkT& z>3u@#vEdpL`Nw)2+2`4oaZNb%gCGnKgTl@K(E?3nBc4G?xuN_69AH0<-=-ekqw%{8 z@w+#|yx0Dv_mQ9fe=QNe8sm!An2QMwV=dmhpNLr>j7PEB3K?2c1a{;_p-ZJnKv?9GG)h7nL1zQJE@7`oMxShc%>E< z3l=&U>Q44T1jCq+5{c%o`mV>}%m3_S)6bv$=w0}cuX}GzKDK+1)5`;V*}wlNJomL% z;Of(-Fq|OVeYL<#zkLUO{M$YNxI*~OUwdoyPCxU#&%=9u^2Pe`ti+ZW|Lxc6cR3$0 z{dbG%D8cPdWg9tB0m7j{tNxk)`E%jPKXPgM`8_}RBE0jvpKr#!&`vst00yAC({b#+ z1`>%cNByOm1_gnrbTZ1j)F74Gnae1`X*XQ+y;)%6yoq$XJh)BCq^fY@-w6P2y?6#! zo;tBL+hoHRMTzisy=^<@>UpWxvxoRK3MrhDY81DcG^e)qW7MFE=7(6pwUw-8Mfjb) z+jbO-_XPHHsUg1AcB8p)%sWjzdsKA>Y6Uflsa=URdDQEeQi$J5JEm&6oqyhLe_IQ( zLd>)GsgN84L&gyE1KzP-h)iwAxxQBeOw4Xji_WUoL9Wp$VTIf}zD*s={4DUo#%>)B zV!bu@$}HC!PEtDz#(fhP6J!FzL_; zr`B-!kyVXE6zdx_cgM8|rTrfFPedLlNXl8@vXKU(Z74hp(K~n(7F47+<^WxQ1 zNEYadNW?1zyox%1Gy7i}gl6y{>_I323M7yR!?c+0Syn%l#|2_roCK8KKQdL%qMq z^jFA%VJ#v=qNl;2%9iKZ0aRNyGRJJ!bF1M<0`XgEGd5b-b0b=9H;kzgcEfb%P&C|dKfCk0)HVQ=fNwlO=S9WUp`g!cJ)UI};Sdz9xxqDC^QLITQRC;|Hw zN3xIc2iPo3b^(m4xN%VYEsxX3{1^;mOQDSCe=_3p-T8Jp=T7lc3q)x4w^neh);|gM zk|0q=^}J1WGNOjrikS8!7~`!qis;f{=)}7WL57OIW&V`M=hA*m{dVwO+QO#Mm?h7L{65BY5mFWA z_-N4ju?xX4=-)5nQDpg@Dn8+H5E$`4Ym%$-f7;K4BLB!Grsg}Rgx47FcvDzm=h@p!1=tP8CsqXvx2g^;nLSE27wSIg_@m; zhbY&P$}%4&=fS$m`D`0mn4NYU=(L`#G}*YW2XQVG_P&an3=7Mp5an^oZ1^RB8&3{! z^T`2T_{fI+eS6N$G}>8U{MS|C_e=l7?|`TO#2Q^89*;nA5f9^xOpcU(=dw0L`#&huY|Km;5zqxm- zzz=`LubB-r)jy|%Mv7pblA18X?v8|Q!;|W9aA&}GcR)C~IKaR4W1j~PfA0C}FVA0H z!6R?F;5GoE>`2GmL3Q_xjg}79ok{au9BSBIb|;Izq3VvteH&HsdjjvRv~CW&N#l0{ zTNBdN5W}|P%Y6PRxEP6G=DXH8CVLX}JKry2eg>%S&EGZ8Z8VCBKOn@NgO|^bv-94~ z`R$iCaQmeVTzGiZJg!MC1N8x6>;SIryLCt7`tuM&qxOo~-dI2XfU{+)?8a`{jj)Pw z8PeG4$nN}O$A6Eaqfh=k4a{Kdr*Y2=-qSNXg2*f`nQT!eH>0=^f&uULD({gq1kZ96~$3(*D+s~M(bqHJ?% zYK##X_8QUOhs<2KjbxSG*zJF^{p>J|_qnO6ikGB48Z;DB>u-ngX9_{$DTEecF5ctF zmAY{XTFo|wVn6`lUo{7+_*<-F$%o%?0@t5Dfzyk#ovCsgL;XH-;m}ZP4&uQ46ZaEj z)6rE4WHEoR8fp8)1cR`fVt$d^LuNbLSdv_g)ol{9^;>oFgB%1${XEhTBkK1#{>Nz@ zb9*$$^PYd1_sjM@Tf0XNVqh{I$ljCYpTR-!&1<+_hn~)A<+l`C#o2C*ahQ%6po#vi z_E&?5ALh75+}Sxmv-eGWL&oRJdc`$!za-*yT5lR+Z^$)VqjGqX z3=mf3K*mRd;cuI`anO*^>?_212(9zdAmVi%hoFrlLmBTyh&`0jX?kULS|&!kj%*L3 z(?Eb4ps;#w4B}mMHGX-#SH~N|AC7UvD(6o@%nJYp^Qpw=DEApoMYSnD!d)J0e10w8 zGN5{Xt?sBFf)K3uPCqBYfX!!Xc4AQP(tg|VC8D0+na{Ceek`9j2`Q74o<3(FBx%fc|G^GEAZr(UxMHH`BxqB8cT~r9+dLb zyaamZKjMt+efDiv;9vi5o&x}Y_x{~az|VZ|^GfTAE^s0{u;216*PEg*(6;b49wMy{ zc1~pn94W*R5e~w)>QF)-5eNZN4MpeN*qZeApZt7y^ex*0_TPNld*PLj+*33`^odXr zz7_maAVL-^*n*XB<{(I;1TvJZ%G z>!mX|e{JRH1n)FL3PVB&q-%r3X*%e9Fgy;M}v5$w}Jp{3u#UZJL^QJ!tI7q;8zh|fz~Y8)Pdvr-_9dW+Jjl7 zriopq**~G!H!8m##dMvfwlCGl8&6A5^)HA9HT%r8p!?VM&i5f1n(Y`%XQwou$*}vi zzpc4J>+dBM$wqDCI+h!rVLE*Un6=|Wc>{a{dcHptuhBsj-2bBF)wd4TJ0IE8CZu3IfV;GNNe zn^rQPDD&2?Q-gY$YiKEypIWiDM!p2vz8F#WlZx;i5r$f)I!VN+vY@ueQRZI^#Hgw{ z$TX_PiRbH0j$8Bf6*5xkv?rfCp(xB3Qrp+ld6Njg8ja8*fF%N@lz-cV5$7RDAMyS?!9Fd|c1ue zjy@8888uy70@x5k@XX8+NHA$|*NI`NeW)-VjM6(BV#)WG0cIS3Q+sfVb2UWT&dv$M z6h|D@h$(8AZ20RHMZ;D4Ee?8|sBcApOJ(-~oS{rW&E~LzrlLZ_JX1t`ClRC49x4gi zve}`2sYSw#j0(eQ{&^SxPA($AErPRqP&@E(zIN+rSfNANUL)P9Vh)@4QK1@P$?p_U zP9oNRXhI0ee9aD&G@dVp0rhyXP=olc8GGtRM2<-2h_|siIS9s`iLr>;Z;sq*?1W@i zFwRePrO;+3tC+CVkCXeuxT82liN-M~ImRE^*V&|X%AAML(um`naiqUS)mz4GH-LL? zn(X^PE_G?9c%`R(>XRr+DrS)nD<~n)ZQw$nApYe*Zm2F$IrC9?otTXLgh5qIoUx}l zU$l%VZ7;t-Py)Hq0Gx5rld@@%?7F|Q`e#NPUm>0wWTRq+#Wak1u*eX@aygdj{q^T2 z=e=rX%W<7Kj8W85nM(xi*jOZ)gZTMS+HY+>QyS@{Gneb{ukRl&X+vPgN0aa7i5%se zNX+g{3@-{v8P7wic`!j4-V!a&qR9lpPc2#3NcMYG?{9w)DGdkXKfCe705_k)ZSl8F z3or)5Ca|sUB$!~v_4m3c{QmJD_>1u7Z~xN(0Pw+g{VY89^>2f>{(Jup{Go6DM)>)^ z`a|&kpZI&nD&g^h&pwQ=-&u@Rr#a3DU$fP(Zsn65?ajXX?x*0#zxCIrghonJ0$Ils zV1;x;cfB$_Z@EV*MDxi%a=Ci^TQ8o$kAK?- z;N|D<&VFeF@MGWn8`a-^@^|k}9d?99=cwB`)OMyKM^aFIP{^&1x+Ck_v*)LxuZnoy zJ@`An`*}FIw3_DQ_Dg5G@rLGZQ&u|E64v@7vODY)gw)j0IDqKT+I7^KEm{`hPVZ#2 zCG+!W8EwOgwJi|SIN}<84E{LHTYy*`?~}GK)CVP;kiK)P@EGh@h;_OC z0u5If>Kq+d2w(R3R6~~Q{WY{jL{K`~$MrR=P_QM`ovN}!a!PziMh1!aDm9`)&dYQV zFM1^qMMrP7-L&=2_aBkjk5SPfYUTo!b!6(sbxDBoeoO;B~mq2m>;Z_9XU?+%!$Y zdZj@~E@J|>dsdI{AmqQ$MGo)QAKBEaO((eUw;l2I2-*HQGn|B^%j^tZTkS15BS;1Y%L#iO@#+@?$X>npEWZLn$KJB3ufPx}I@` zQ*ooJ*%-)*2Jtc?orS;UaSjo+>v_fQT2h$%L23i`VVDtfQ{>7LQkmHrswL zs`EZ4!|MAmps(#aj>q`!Rot{iCUPVNHcT)(yFSc}N}S?!n*^s80D-fAB@*_!nHRxu zg97QRG^Qaq2wm=mic&Bi?H(dv5&lUeKhf9+ql{_UF+A{fts>P27H{x*kn4F>-#L>8 z0s^gQMwBx9$L9|j8nH=YN`?mz$l(d$yPK!o+)r`(AfU$lgLbHF#4$G2kf&J1hJ!$W z4D39@W0eZ2%o>KI!x+bxNN0eVes9I!E7TD#9FfQ3umQnApx4Nq5y``;r{}mrgj-af zLnSl7Y=%ZQ51bfz2wF;^`MFW|vtta)a-`aMcCrTsbHGS*J*-hB-Wt{*&a>P5xl0Jc z9fGsF+u|@xak@Y}E9X}pJ`XF<5rDga9DrJe5uEo8DDgT+iI1O!(%wi$wlROe5tjl{ ziioXdu4IN8?09LMS6*nD;=PH9XGS{X?)<3c!*=sO*&T~9Z$L?eTAiCDGHyN}&i0g_ z(JX|QU3u3verF_OOD$WWCDCUN8Vp1ls)$&{jt&?=@%ZO3MgY_q@(8`cIfP7X>U^NW z7(jD=CD!)!#En}<9#u=*SkGw05n2XtdfpUL)5y0$1yC02L$l8gViA*Cujm6OutH3u zj%);n`d)bkZ&_A_O4OyKtodje-q6q3qR(JhovqzklmEJnQq(M+GCIoA5?+ zJ?cydTBC+$&*gi}OkSiyziG#UkY^agn90Rk*XV38R5X4qv3Nt{cl`a$Cs**oM@VO6 zs2F+l2lE&-A9&&SYyaAR3ZM6yx_AQ0jwE<02yLy4BDu^8=rq3zVP3C7~cI8AJ;V{ zOvEp9!~p==ku0e@NO$-3xdER0+N(|H-J}`0`@f%h;U0YIg?p`dff%@RSL*2gqrdPe zc=`D|!f^up!TWB3Ru5D){ER@R(LkcQQ`$vhnOw|VYo`F>Fx|i4o30u^4=1YZ05Qtwg5!e7i zq-m#t$F^^&kvKJF;comjBswXGC8a~IaKw?N(S}lY2~&VS3qU3{{LFD_`gKTL;NZlkt(8@`BzONx3$4-z+N;44yn;jM*K*i#B~-z zLTWNIja*wwwebfs9%3g3+Fd}YCi+lnt-k1JW)s$9#zx$B0Gl12q)f_Bm zGa_61+x6)-v3+(IU~`wngNBA@H4j|lS79Ki5oAUlg`a1coo_ULi}bHL!icYHD}P{2 zmq6H}d%PbEjbAq}p`4#+Xf!a**kCcB1^Y>rC; zp-n#WPb=#3#zPlj*~IIKe1ws{Ez}m{^mB#K_SP8H5(w?a@5uB`p_b`FjCa*1Zp7%C zM!04_q#q)~erTHX);>}zdR0EfLp;aNE%V4~KDP0%WH847Yg$nlHK^A5)e*n?>#Aoc z(|%CpPBcWbmPa3uDh4C&Ux`7zIfE6*^V9BL#dlaEiktimXNVv_k2js)RR$LkcMe!< zR80jPt+>zr%VBU-v_Q1)lx7uLddwe)d24e)z!u z_D%o*c;&;t13&d0-v!V9YhMF@>@WYvaPtqp3BKj;|0w**fBQecKmWlWI#vje7r@ELQuQ@=yyI2A9&}>aQD?st0`e3e#1sTw;_gDPaf~=1ps*VtFOSx z#i2S7G@b35<3Z8k!Vs_gI=fAFhoopNpqW1#UncVO3DgRVjby1;}mzw-_Tt>dmmOpQnnp7~IzZVkFFX&!lpIzhWQ8{{uyTM(9=!C)a~P#nAGj`S8W zQ)`4_s^ydiy%NEP^*FBtV#?BRLag-atVWcH(O|VjETD&&=ZVpvA)rAtX&NS6>?}f9 zy9Hpy-0Pr)DhWG7=i%N)(mUvyyzo1 zz}NO2WHGrx6mTTA?QeNUFp;g<&b3g{IgA6;9q$uDwL{z2)o3;}rZtUK9Z}HQA0o%k zVyzV^5&kC^26*_H6S(%wiLn2W(DrS=a68Uilbs`|GIV~ZY7|Q(G06Ci*$HwG5x%zX zyfp}Pgd0k2UlQ7bI2Ua+i6#)5Q&aNC(5P!Q*Ra<31w-4nVSuO+%Y)P~Munn|Bg|J+ zNx-0JTx^IbJZ)d7HNtB|tkh(#wS7&B?g@TY5Ufi%Aktt&Dy)h zde*dkp{5dSHQ)pn5^^N8C`^b#BcOq3nqIF)N{#k!h1fh(gYYMf5kR;ap$U#cBesr@ zM#dN175Q|=lPWG&5PP+9k)>%aG=2r5R<3IR!MI^)Do?@wgowvR+m{%ccK~dixq@s5 z13@nB+%TYXe%&D+$vZ#Q5ED(~x3Ysm&yR-vymY-vR=!N2?Vy74-L6j z&4-NV1j5(WD6Q8bIf%UqVQu8Y5Db4yb-~D@wx0Yg1_(>Zh!mYKP|Y4T%nMdyb^AQZ z=VGGht1xba@jfd4mg;wNHLKBJ4BP#Th&rxDVY-YoaqamsG^Q=!xcV)z#&1O}pD4h$ zc}(3vBIe!?5IQu4mBKlW_PX|4ym^V|&ou^!>QMwkCufY*n8t=dIbWcC&gK4Mjt@XJ z%o>9WYK(_yl#$Vs}=(_+t zX+_FVju;wYtmF0Df9eb2>NBTP$J-0d}S z{g>e0txYo)|L(iyXSA-5f8aL!=)duP00Q``KmRy<`Ja7k`rRi#dKZ4=UwtnC06hAK zFT$Vsi9ZyM|K={i4}I~k!Y}}Q=exhC`rXfb&-3t}zw@GApg@4n`-W@qd0%%09{Zw; zaPh_(hBd;iPn^NW-hB(+_fs#yZ@%+oI6L!A>$CsLL+}OPbPXPV>qWTy_zA4fBi#K| zftNmX2R{6NzY72F|MUX9`n&h4uYdEOx(?s)gKr4m?SKES--h@9gO>mi;oE-fbK$9f z>C*JOcmJIi;ho?8yqTze=!p|}>$g4(Z}`f~aQ)eN9zXqwGx*qhZo!BC>8tSWzxyJb z-O^PM-}24Z;ZOeHGtQ3=MK(yq{cH!4qF}9#*G=(oqa)tx!y8+{zatg?SeR zlFp_g(L3q%e*kq0vHX59-s$l-5wm*dvWnO-wIxwgVXxB-6d;02tNrEABlX$&4cA6CeXyrN~DIGtEkfL>i^QynoJ)d(UTRp&7_U3o+|WT&3A-G6gV7eBnnq z64gUcbLIvOF>Agb-%lO>vDQ3}H-!B;p8dxPk(#l8Gb0R(7p(O>0MOaC_-OjoBA|ZS z_=|8f?D$guK^@-}qFJ*PQQ7CZ_Nr;eV2=L>lnC%P2~L%t)aP|Z{##zw>y{ z{tXc3vJpHVg2>vauaNsoC94mx4j3K+e(&TH16mJd_rL+)R*X$$qgZ{{Bi zjcLoxHHcux-YNNrNJCilyN(pD%zWq@Uz)D^W5wq?ow$JYSCmjM2y!W4-Mp7c)UKNFAq^TBUd19^%EVpb7y~RS#bdP#sBVO@D2a<8>j#F z#czKE-u>gBfR}&gZq<-G+8+3Bon?$#Hrf5!8&2Vy{y+BKJI=1E>i_@jeWy<{ z$;_npgoGq?LP$W0LAn$H1rZQMP!Yt6f{KcT$HHTMP(&Z~5gx>bNH5YsdWp1T3$wbwr92FvexeRX){b(onu_nve1K5MVN_xgO^|1||8X4ZKxA2OyI zL&j8N+L2Az`oUh@^@&y3{zktScNF-h0$F6)28`LK0sEgj0)PI( zIxN1kJ<$+i7p~9*DpF0L651NzkWY@mffwlQIIN)t!zR>V#xcWi=qE?xp3B!_`9nLs z5xKvMuVmE?D*!M!@ca>2aQRqv2@S1Pm~m7SW*pUohpyUy=YFx(ugJFshhI7d^FKHu zQ7^LlKDru1Mpt9Xp+oSNkB-KjpIL+D5AO7hjsi>*UjZU3ru8f-b74WLz_JOj{9geAE(zq+&EO!HQ@I7LvE%Zvsqg5|!<&N|YS6 zO~(2to7_`aK_HZHB&X66pT=?t61b9+c#m*M%)ULIr7B0mKY&PDp{5I zQ7~MQ9(nn+6Sx({y2@sE6%|#SNlJ0P7b`&uqA)-zLad&@GQ}w=`M;~!bJ~TmeckaY z#O^gtM#YpzilWX@^jc$>;#aaDQwF)w6+$6No@8NLJ;6@ny2*5sam`g2HpnRqj!JV)wys5n6x@*Sbl`IVzciq9qDtY2dQ zD!2?`-ytAjf?I>CTEJL~fj&YMV0L5SEoBB>{#M{pvhz<8pn;njsHO*akwzt?gHbNxI<59<5b!14LDKg zj9+>FZ-(*f#&?hLYq>&BGJfUyqqW(LVrzJw5oG?FjKT+JBZ)g6i48m>7_koXH~kD^ zE_^m{^pu5)1sM|$zzT~fx3n)9V1QJZY)m} zN8_^HwQynl;ZVEZ8Vgr`oC!FHu=g{{^CSD44LOWx?Gad~W$*0=U;|w-OHRUQOb%lj zA+~L{!r5pHXp_wl_7$_?jpdM&rrw{!j9=#bsI9BS-1mSZPree|nGYJF*jD2>&u2nN zhq$0-#JB>sZ=wvwulc{t_^ll_6mS2ZYcO)}*~!mlzvnaz-)#yWyW*Q@U$HXyw{1&T zVEiHTP^hgzeQOJLu3ew`S+m}K3Z|cYtoplXU=Z70TY`bEE-bm_E_ANn_)p*TJM3$h zW7xFGc<_^7MEB;c|K0`t7yQar7>4933gb7{IYnT0dMd&6@USbxq33DA3Lm~Yp!pu!ihhcf_pDpjU{)qB^TY>F^Jls z7Bxc(Y}2vWPZ;PfmS0n3%&GtuLFvAb)+-t$^tKlPP~iPa7dF@z?UJ&oX?zXN`0aGm zH|K}V5wq%W`mcAxuiv>8JJt^*%eJ-vyyLpb7_)B!dwut|LG*V;7&g8-S%9ssw>a+V z3D~i&4;xHwUOO2#y=Mj1KGzjQ?y8JV#(*q8PY5X* z4QDFD{~(QFU0M*~AKTqFh#{k@e0;4_d7s}!IomgzNm*i#WE;u*N)^xI+ffjdDtgn2 zDCNODO;`~tnUGm57N70wGk#0xkFr9>gt@3`J88?Kf%u&v6d+eYkz7xuN>v0HRZc~4 ztoVq^lWMG2jGCn-)JT1*{(fOzZ%oO||X>eC8}=vmi;zcPaebNQM|^mdg8FxnkU97?vufD`R3O ziZ690Moh71tqplSe?XKzcOAxMN_25B9UtE%ovZFqlT*x%Tk~hT}1~UU&&C}(Ihn9#`ldl zgUwNdB^%-nBasaMUWJq=juMU{&K)+1=f8ZM6~A|v1zCI(it2d$6-psF-V&wCr;wr} zW!LEn7WZ63id4ox7s?wJ2PC6YjK6Lth{tOlzl8%z#OE1o;ubUNwedqq{8;)#`T{E% z!5obHA1EuJIq@!KtTF{3V=U{18BviKhNw_gTAUv21qKI6T^}ORZr;3B%%2!D5q!KN zLXb%+b4UYyB3&wu^$Y6Qa6%OboHW>_mp{7G8_xKJ!uXB*rLO2KJ0cYvM-8b6D^jUg zD~=lp^Vem-JGS?A}cmewlaT=+eQNHUEF?KitEMTK9 zBQV1u3bS(4e$C?`L=^EW0s@Np46AI{ks!=8NAA3lw_`@UgJ95W>w=!*SDZKbR^Wa< zp3gK-;(u1Wcg9(mJT`V{{Nm1Jae*Ug!(hOF6Hexf1mBSpckb!_*#0<88pkP`g- zQLg8-jx%UpYtXhiVu?#u|3i@U{7>Hat!o~R6Ry7ot+RIr0Ni)sXV5UJ6$gImB8;6k z2dCft8@zhsAMosVevE;xZoc6%c_L<qr-UB1{nuV&`+JDIVpLpZ7=xg7BKVN*=zjs*ie_!!Sv};m* zA3DSHQsiJ~vG2JfyiMOVPj=#| z?{C1?#l0xh8caE?35Q-j4h&u0tHwL8pO)BO+k(NtmyE_A&wm33221blz|wm=Fm}HNocY`7?0s%Lbt!hN>u3GJ zXmcs!cdG-=8|iKOuKG(S9{bKlY+2NUsyd6QZykywzAz4rBhz*~=Bf!;|3VLTtm{wu zTqK;ltLrS@_QkOn=!x*`&$eL0!X7k^s=~Yvjzr6DwT`0D;DGnH;?7HZlJu%jZ7}bG z5&V8#xgIay+?H(M4;fX3!#_I)d!5=`=EoZ>xO^;bJbjs35$rRZWCf~F-UNG`9AtTg zm766HV_Ngax3|5B{_Y4h4OW!h0&WFakk#o{1d~wU1Og9NfGWa0S?a4Xb#fF0zJkxF z3^8Mo$;u8|Et_l`Z;vTzW0kPn2#2rG4wckvj9*gjx5Hdc7BBM{pis)Sl?yVmBHhaS zYZ7}KS6OBP6}oOoXxM%@WiFdSneArD0ksN-7^58PR$8D8_Ls)^)mZO}6<=k}?k1U3 z7-TbkjT;}xWU#Bj6vUwlZYcrP90@qHxsrHfoJkTg3pKozxDe79Io8%B*i(VcUsjQ? zC|`q?N!DFJ^iNQ-eI-LoN{W)_B*cJ|mCTeA|BcBdbL3VCL$KMQDRB6P0R_~lzS6{a ziy3u8Em|g3qiIZ)&!(4*Su2F0Hq0J$$4~McXoxc-gZ5=|e324Fh&U=3v81zonUbzT zwy)gqa@oEJD5M5(m2~URNtNyn<1cpFtQ+kJ0e-lme5tK8dCEa*g&Eol$Rj|MC_me zt1T~v6FB3&f57V2wM2C-5Ca7@a=a}-XZv!dvaX0A#TLQ{X0eSG)h3|aD`bziUca=+ zWF|_+Dg`BK(AzJ-B=oH|4RhK^@^NT+jPaC{GLv%Sv^Bm`SySc^A=7p@vCj@D^x`8!L}o#}gtypD{Lj{*)-&DBw&JJMowdi*LmNC5^e<*#t%u;t9(~@)CVvx9r5+ zC;|#mX$~9TUmNIulJV{a2wMQE8vxVi6mL8I-Bs)nV~%siFH^h*8NZb=I+JcLn9CJ2 zekq^v>p4Og1e{DX#;?!lG>+pE1@euUC7t$r5x)z<5lJv4$qH3oKyfMA#Hz!XDaS)L z`=pdNtSFT=aU^$RF)SW2g|ZQOmSc1g--d$Cawaqm^Ij+#g~ZU5C6dyS&~;ogN*w2o zS&k!(aAdH-@m9}gO@L`$iU&y4c*zEm;ofnn(w{P228~fRkXT=J&YwiQbHCTtJSlr^ z*2j*B^%UY8nC|zQYmT~}k`+KIj4wc*)vw8ze+K3vS@T(BtdDsNWuvYy`-)dFUYUG{ z1AqQmfdgUCaygq=5LW!k^Uh)V%6VDHu*&G`5#GkR$=E7 z!P@ZS=I@877DvoMBUE9`6xAkB=kJ_Dp~|3jd;x8ni90C;jw;GaeE(0`_^lt&f)j7} zF`8#gL$SXf_gwHvtb5{F0Kkg79>BcIF2StRPsU#7o`LBn9*viO`5Uab=K=I=Yr~|s z9*jf3dO2!_mNsvmzWSP7+ErWg=#%*Cb=UiwUqc!(^_T_N{hcS`i2wWwHa`Cnx;Jn6 ze_}(?R##)(`~%Rlb^E_}SMh&a@hcTZtO7=qQ1Xg72nAALVAT3Y0q9uQhriyi1#`|H zmHhmW&yL0KPG3@bUt}qMOCL~GZ!q^mquH-Fz0{4{KD+`{EG-TV_5+LWYQwhWy*Tp^ zGm_-3s?K8n^G4#4udibjJ(}u?NXwiksCrBleER82#-PcAn-MVa;6{wypKsVc`i=E? z_2%u#ZC`wM2Pgtg_+e_JJ^9d~XqjG%ZOcm5^yB9?pmWne^82o>gLwJ3sp7w5T_0Y& zehU_SVSMtl3G;`bPz4MQr0J)2ZBayta?w@zsO&kXdsWq2%>T$J_L2>M?Z(aLzk#UC zDJ~8a@%kO@*tWbE=l*F1Qzg&6U<4kxa-HZOe2g4ExfZ`Zb2-*M-<58{-@gMF+&>d_ z!&Bw*#CeU5l8P{VQY~tm(%pShg!3wbh4pRHNsMG#gsrJP z#$6tBFv#>xOAIM~UEE$7js{Gz7byKq+s}UskLeOs%FN`7Y)=8ADY(gH_-V=X% zqABBk%c}T{%H_1uIIV2Yg-VqbjhaIPuShQ|5aYZ-QRHY!#w;~>Q~~Nw@z7>}L2TUB z7bd-m^T6}P6*yc`K!n^0zr3KKBMNAlRE_%Kg|ecW5``|=O4z_^Gzf#nw>4^^B&j3K6sHJ;L~0{dl%`GuCw7r`+DMpp)# zNGQ-rUsp0l%mc*zCL=3o$)BzT7|R}WHA)q58kAQ)PcpxAk2(a`xwIUG8z2>K{usxU zi$)*5FEq_`h3-KnGwIA?RuE54!HTN16zeKRcNB^o91D*h zLSg9^*kuHcOeU%b@A{Zcys}$JXyyG5-RF3%#AFp6yZNYc-c0D7FwFz`E3y@|t`)Pc z*j3s~i67)#xV$}leMU!dht_67j9(&+5ia6}$g{H)y(FBu+}(ILA2Bw=VM<}TlW~;& zQCgJlB2ZF?fYNmlNhbvEn8FJvWxgZETU9~tI;JQc&BPE-P?7wy#pEYn+8UmzhCQu~-Rn(5a9n zQWO=|sO-p4@r%43$?QuKGUIPB!x-3@MHmavtiORl(3HDI+;3fCA{AIkrEZ|YQ`=X} z%2nd(%@DIaRon`;ube{&#frN)sY_;zH(Aq)@a0~CAs4UaFinDNUxo4Os9HeCWW^Zc zFNA1pUy7&eCi_`6ISknnD=cL+N1;+;*X9~ zcP``CsWc`sVMVJPKE<;wSzOjiwy#iPNd-HyyKBOv(RDl|{3Moqo-8Ep=$G@I>fkO|E$1eESM zMGqd^*JVb!F*efsx6k&)F0y?kV>UZZnDW?e4OcKqRbOvdelSu87gtzNTP&XeBxQSqk+7Y+uXr8HMd@sXS&l3rl1? zLlLRuDag$NkYJ)3l^K~lX9aLa8L3#S5{l<|&n|H;2{7QSWUUH@ow7;KhCj>qEhKw7 z9#0c?Uw~E3dFx#1n|`+A@*l{c%aYAtLPq1bOQINJl(_x@HY${c7uBiSvaGN(mNv4JG>BX7M@=20f&HkQU=x$3ej{lin( zQyM2?#k$vDHH9d$ov7m6E7@Q%x;3+0e+{veL)R#s<4mBx8BM{Rq2Sl!hQCp1LyT}E z*AtZap?hDAK7lkD!b$f&OUApLOH`x`)tJ@laASf_P4a!L$yl&AS@7!$t8P4XsP2FV zBN@N`e9)NOv&r~@&NR2?Z%{lNXTB6#kF^2kHOG<181BHMIr2zH!X(aF&iM7_?P9zN zIXbZEw)Gjm@)$Fs({a|%XA&ok^5<058jKuYz|QT(lrin)*ZTRp$K?I~k^5Lf#*f8` z|NCP!O&pK@&Mw^b{!6fV;VbHEx4iTkZaMA!IO0FA#Eetkj$&UwRz3I_s941Mr=G`_ zR~BKP^UgwD%W(Ylr#JlF&arLj3XI%)Hfo1AslOk!@17XG+Y}5LI~t}?K*!3}Sb5*W z80_s+Utd*MixGRx#>l<*K(W6M9dE40#^?WvVqbs7=QMn`DQFncil|t`#^=&a@~ZlJ zj5}x!hVM2N16|$dSh336)E+ng0GO&m+48h1vAf>-+G6zY>}2OTX6}AynmiHpt<9h) z!uqG5XPff!t9iyWw9K52#!(}%Y2ho_^ukNYXZE&tVEf`_-rv*=X~dYh`=NRFY3O)k zHP$}<3);g-^Dh58%9*2X?zWKtnE+BeJOC=q%#h(sCn9A7zGp_d0%7p z<7(f{ul8WD->+^i4iFx=a$UxRjLMbrKtpQ*BWKs6zPYMg;amD@nO5h=m0H6TU@9x4 z%!yH%0T~jr@dx_txcZ4sl{rlytb4ADZTvQltirGf)#zB;AJpJ1y1ktLiaq@ zUb*p#lrbkWadH{IE^D?>R$pgWeR0+u!Pl3%7L$sCQ8169C<8sJGBuQTg9+YuS4rh7 zaCD2OirBs(W;;{LfGHy-J62P8cndoMKBzM1vqajCP~0d?su1IZ_wSHAC!6i7EB^=x z`#0#U>>(+ZO=_o?gjroXXXRvJ~qjv(XQWBa;{ZIEF5!r7!HUSt(u$GXa$ zeCHjd{UV*|#F6!+R?w3ZXTA8vSab3D@_1pb%l4&=IInap(H1c48HCvbeiSM5DVNb61=4|p0Ze`ZU^s(NRV=ILC)i%H zzXsX9(AmBqU#U(3Wx8Pe7Ku|H_oOG zSTQr$&4=9aiiEOKHY`(2#EKS&T^f1pUU!~pRJJdRZ!DjNr^Jj@#T#+85kZksiO&~# zlc%6@##>_*R&{`7T`aoHPZD`LXUb}hN}huNb9UkLCswE>mA#TNt=i}W@>wN5ha8|Z zMX)#C5-|m4F^UlxCUw+^^QFi|qm=Kr4KPt-Wop3y)urnn>~kC=tim89cTw6`Trr0i zq-=99e!!1CI`mL7e#vvT^5TO*ZoU-GlLY!giS7}F6mk$wKAh<&H(rgx{FQ~Pu3|nY ze2lol9YH~F_Pi-BTDDS|DxLC@{wx&9iegVHNYla%jY%x;bKd3-@yh2c%U&n0lcm6T zE8@2Cm%OlxJap-mn0WZXsB3A)nn#{Mp|%!# zz3<&o(xNi!Vdtm{I83xcTpLj?L4j0sz{VuVg=;c=*9M{6D^c#xbM3zvFIPu17li$@2Z%V$u{j3YI;h7gon|q)6 zDE5B;ncjN=z{)>Ag8M%58TPZd z(@UF;4Xss}`=QZz>iZjWRmnrgRP+9@eGmh^QK~=`*VDPtFMenoSzX%rO%ggq@vE^N zO@Q%>w1Os6?phIK!YN`I&9Aj{t|KuuI*;V@ruIYmJ)t zAcyhmwd1xy4D^!2U*jX(j`ahIvqLpH)(!;kYsZ=ak0}cn^tBHL6zS!~nj+!hZ*9bh z-s3o57Vr4Rn5LK_5Z}biWcG?mVKU)$Y2zw;QicpEiUOh>28&l}9$?lLgfhbf z+Dou~W&0adu}wP5$z@(L*>VChgNXv;lUyhXRQ!e(996b2vLL>uGOJ#fK|^82uj{Nq zR{0A-1nz2A1zPnH=SYRAL8NuG+*=nYbZGf$b>@vYBitOUEtD%3}K(Rrx9v zlH_7JwTfV&*h7GkD-|C;Ls>sxBFenqQt1)gzLLyKuTGylW}5rlkeJxH%+&x4AnQ~=Ld2t(*`8Ev69t&cA?1lsgcSH5N4gMf9R8rrx^&sT zrXsel(tZx}(%o5%6%p2uY9E(Yo^!TuvXN;+%4ZQTESKITO3OU9uc&yJ3i)J{hO*}y zpj1&n%0n&{zpf(zu{=s=`%)kx*z#hrHM(M+H)zTn%vA6x3Pg`-?SAikuw?v_H7eWJ zRbpo;B9iBZLdp};*}jF?0U{93lN_H|pCSs(1>Er#K%u;;Vgqbnx7~~)a3LkfWGu<@ zO^lhA$&#|n%aiZp`{j(cBV}fLavwV_#W}VB{B=RAMaXc>+INR4{MjBIMGBbw|6CMwB_O(#n z#BX4P6OS|B(%8NTDECa({7KnJBEeV(@MEonIU5$hXZn=A5stuev; zPAc1NhzTwo3{0ToT9dns#QJtr@+dW42NZ}JMj>xw6b?h%AVY!eY(S^|S+QD{{hr-EBW{nJ zSA-P589eTc7s&Y$X$2c5U$I;%E_8keG zami?oT+*@B3Wd4i*v9UuHQd?7>W(KKBfR`R9t%9Q{w5g4^7?{|W=o2#1kdA)=;v;| zRZYD?>o|*@ZN&R3iG2a`*TZDJ`#*H!_l0YIjx`TIfdenS2xAW14`<&02Rwhxf9EQ8 zs~SohBEzOkL|scW>PNI-$t`zb`5pJ+pvyjnJKlTI-+XS>jSZM{@%b3J&mP#mco|mQ zbwAtaJo5WrM@`dEYW9IIMgD$%S_g(bauEFn)J;U2zcE5H%?F20N)|b$~vlDln z_c3h#>#G2O$wwZJxu3ic{X0AH%zyp}+g@7&7+~B%bFt3_=isofe;(_ed=6b3H{gD- zc7NxI*!03nSbpc9(Xnz3M(w*N_PO9}9Qu{dqGo6#7XIW{|K9J-(3@m21|huhDWg(X z<0d2(YZ2k`Z>`74Kbw~Pe&2IP;?>`8M>Ifziu4G^SX4LiHy`YcN-Ds>^$hm-?^oSm zc}bS0_ys8lynvF~NChTxmBFDc0{0_ohKOtJ&r{rxqwGpEl-chXj$^+yNo|+B?!hYk zGZ?>q#bAK(TRy#-M!sS)&>N+dc8X$eu-BI=)YMzXBlL=2ItKkkr1CWdSsUdQ(${Wj z!(eZOqrN=O+kj7Ec2fbfPa2NdCk@A%r@L_LC9BZ2dC;jiEmxEZCDpDlezTdr@D*|3 z8)Zo)v|B;vlwfvmA3)RiYS=0ht_*hBVI&n^e4{7NO4h6VjKT<5Ba}2I<|iwxDwJ7< zoT-+f46K0dn<_Agy|1ijtXR=R*=%1T<4K5I1(G#z7=DU;F`(%57_N>2RA;y&$RG^G z`_kWq6(A{-FA7$4`q!b1Pm0o7Q%v~xy)uR@V@PJ8gWZX%$KHbRDs0*LDix>MY+n)% z0;IDC15C_H*uL_C3p0MR6?;+vmdE%l70ePJUjk~HN)+v$(pM;yd5v0)|hh#*h((R0Sgo1Bz6# zoh+t`-VocDD`NB;CLJ5x_)L{3eJO*ns;4l}olj7q(pP7!GA5;DObg{hmX||3KDrE4 z&w(Ukyp4*kLy4~VMb`5dQp~E%WnZb{D)h)>XNMWTA>|`iS}2NNs#GycK}V!?DiL;Q zNUqC`^Fpy6R3^Eo(TK0)`pyPnwyzv-No@G>`<*h6JytVGwlA^#o+J#yc_3C_4sl(g>g2i`Z4GPtzKN#qv)MUG1c#L0?3QD6pCQ0WW$>`LS zvFyA>zNA8;(_@rKC=uw_+$lyXxZIs+sen^i?NWg%;-6FHtuu0s$j_~CctNTTj|eE( zI8S%R0rwc`XdViTuOWqBQaEZ2Q`i|-@$Wh;SUo>a;zl7uc~^`Qycb+WyYsw6g7s;P z?vN7CFM^82^2TgXxd-s`wz_f;k#qv!d54Ezf>~ZgHgarouU9^I&kz*6k;Blx6(o6 zv!>nruH@iCnalQMGaMepdZmgsC|`%0=V=mb|NiLfVb)N%{aBt9aL0*+qna2mTgMn| zTm|%Yx{i_Iqt2xN2XFkI_NVKy=r_0EPp6%SeJ(f$dz^I|=707Q%zW3$c5&XpZ^4^>S_T1>z{rBJ65g5l0V*w-A+6j$N&8Mc>K%Xs%)R691$iQb`Vp+0zkuv zRt(>5O6fD6dJcd7DBrxCbi`q(X&Q=+&o0F6XMLFcZu7!daLyBVp=IW7a5=_vF1Y{z zaO>&kqixw6$?uljd{rzD-SfR?;E*q0itf!@amP6qp?yWV zK|JBmc>sVHul*%n{^d={&(}ZoJZgqCVz2j~iD}0liI;zQ6Q2L!&tR*oG3TS_W3amy z&;Rged~^Afw*vs4yz2XS`Io;=-|Ok;K?EG~lqg$KVS366Igcpy*TyeUt->+7h}cU4|=NUe}72@ zTv~A(%V5HlGJ3^~s;G1V+}bBQvFgzsn0$E2zPC_g@Rm=H#lv4)7f_zsvU)obHs=;< z+$J2G=!78Lf9y7+NuFkHIt4td0{`o+6gxaA6=UR<&o*D}yEyJpB zslwZ?oWM4Hw=M0(LtkHy&9C&Jud4_UFk#*hoPNVJ@061YB@;SjpJ|fG_$?p%yNY}> zzRso$Ah}QiQ`)Q-Uwu0rrFT$`ZIp9RVZ~sI3Ii;;rvu9$*nz2s55?34Losn)BU*Q> zQ#a5j&TqtN*G<6hDNNBSq8U?@0u{P`t-8-#4ODPu-p5pN6d^Fq3O1y4crXE^ z54T*;Q2I&*k8ljI9#cF}umPwWu9ER<6Sh;j@uzNFN`+xygU1@9vbRFgAD8W`^*`Rf zjk74DSKOw|Fk%Z4zT(~yY!hWTJQ!8+Ci|OIkPzi4wFA#ri1F*O#KijzA6JFeN!6$= z7pobgFvnf?Y#gU^*uKW-ipBKxe;eD^X!)xXW2MzJf^1*OyrdkqZ@`H`V_rJ_&6+S$ z1n&KHn3`-HwAtgJEpQevq=SPsjzzmazQoE}? z(^vWmrBxC)NGfKHD2@>CTRw-Rs8C4$tc=@|@oU|JB83@dICD9<-z1$4bhdAtH<=`k z@Uh5qC{fwI##j8t?c_!zcOhTqvm!1fLPf#$^_j{6B~qLZQn)|EVVx%IYLD?K+CzR% zoY~13zZvU<@D!-LeQcVMl;)C-a-FHL35vqE{Cv8elJTaYO&v>;Jlvhnnw0TNQ~|3q z=)}O4A50<6oE{ujvq_aK0n|1MDif6}Ta0V{=_yY$jaOKIXADkjgo@m-`wlDO41`Q8`{orme9CRkfw(XrPx+i~{49 zR9GqVT4NmMuMubjcY{E$a|<(ml>~8D8Na&ImeP-mKi|q?{KABkzIr~E#On}S)d)wg zfWprN9Ijk9Drlq1&W8&at-Jf$-XQIk?8NZGrS?Qd4e6Wi0(wMM9Gd}M; zB_^OVtF`$jvo4m3ZJ|t*jNkP8()$!lw&Rx6xOrIL~?npfQ-5=wR?>HBST=^M{-hXeLbklWMdEdi${dc!wu&)opCQrol zlaIsLdHVwZHa@!$Yae?GhkfmG%zn>l80_xBlUIEY6cL7u9gWTnoAP#kOPjnSThTDG z6fHGHkqWE#A4YzXHXt z!uSm;e&xbwC6Ls7_FMPXLALQbbZm97qRCbKn#2MIn0mxe)CiUIy`NiyO)qt`0AD}c zW+;A36YP+ZSqkhj8NcO!JB4*~Lu(bP>kRsP{8DTJVb}z}9d~Z*ca%N>rH5iILxCGl zN*fmk2+JPWfn^WuC~Z*JTa4MK9uwye!QSs`X6H3-{{~E+KLo3u>I_s`Qy7|wR2dSp zE~Vf`_Af$qkKhion5Cf2=f%Bs`A%eX%dN<+;|AH2T>8jRkD3GhI`6(advJz$qO>s zz8VuUQGytq!AZHs2MnltyKLYHV2T9#bw8J8z;#DcctT1({?I z3U-ag`1LAQHAb6PNunsUM8&w*Ebh@AU%l}&{oZB!rV8sE#&1sXr4b6a5aU->5C^Qk znBvz!WdJ3LF)LWV(jmpOs>^1~$(7JN#xE+Vz$U%_sS2bFDK-HZF{v6YQ>sx_Z5hK! zQzkRzl;I3W#-NP?1qB&wUzfS5GICwT8GF7R2ZzYdgVTO(c*Qe9iW~$LO>&dPiy={V z{EH~ZA;e|-YK&j8(VxWWm>E{|6*7E0q8tV-SbR?yzbbQ?y!i*a|B~&iF*TF;lqwG8 z!WC)Ce^2pSKHm@`A;5Ta9Z5*Fx#0>$ZMact)G`0#j(VR2N_>d;gl$V9VR4Yjjxe5zH-K| z%j|Sn#3U5TTK|*JXUzC@k6MD1u!B|UDts2V>$o8l_HyAnRs7~y@fgJ!#A%*L!vmS0N5~W+8aeGJ z_~R^6#V-WomqZ@rSDWySf2(fX>5Sj3^-5Qf7}_7z){{xFh` zv3q?|Aqs_AtmSvsWcz3mE7}WRm(OS?b)F*E!{m7D#u;xt&smQRIX@(ig5~pLQs#rQ zy||+qIkFpVT};NOa0hA~Yp{7W(ASr@@gH7){D*G*&N}lH+;jdXFztk+anR>KiT34h z;PEeg8^fkf!hxUu2&Npf08@@x;Qd|u@|Aevs_$aTQE$c8R~O@{Z~OpjAA1V>UHE>C z*lQLR-So%Y&o<@qmnApffrl^qs`vZW*)uTl@Pjeq)D!TQFI|ed))qYXy`KO8Hofo? zHofo?fD$Kn?7TT>-fb!hHPx7Y^08iGKVr{W0Duk8yr`Z_=Y~z5@)ijP_tTjCw!;7b zU7NP38@P*pa|?Dq?F5WDa6g>=_#Iew`@L9x`+ewGxf<;&R-t>#wu;;2_21u?{C~^L z=@_~9Y&4D?jk;k?n04l<-s?y1H5&l1?ulpB_uKf~Lhol|=k8y&s6Gr6-+Hk3`(aZi z0RTqryVt*Wd6kMD<_%9F$Rtw5Z-{APbC_yQ*4DAI53l}a8}>eXMDn^rJ~Iw|JBp|q zUhr76M1=LvcVgf7j$pqVKYs{TKC(k)noNAl5W#)zPwjXELq(~QrZUE_kzV;^DuYZ^ z@Y{_GyU{$gHu-+k9`&fIvl#3Z@K9rL_RZ5#*IbqS{Dog`!NTjeqIpWK_Ze-=`qIj< za)Hmpw+vNJCaKWW7G>THFKNKVpTqua>^>pYZ7bv{Ah)#An~>LvejI72&&0qWh~e3m9@ zW%34@Y+sH28&_HrQko=#JRo~A(BrjMvTw5bwasR3g&uI1No5>}vZpu{ zH;Iz`$W?~HXAXJ``Z)@|LiwF68L{Li>{W#`4`WPc#Jl);v62DqD0&%7 z+hP1B<1J;3uLbE;qp;WwSKi%}3R(GiiN#EmD&<4$I?rLuDxp(jssfp;Ws(DU{2n&DKU?EohV#4x6qO8( z;v~hPRRU`=vVq89{lalXa`L4_GUqBxow$=I_*`XV`S->c)HDFaK44%VWn&u=2jzI> zGJXq%Y$Uc9@4%VMaFyi-3U89Pm)6gXqv&MMv+sKtFv6izQ1LI*Va!BU+ zQjuB+F(RG!Gr9u`&-=mSnh7Y|gyTuFfnmhh5ZK(a-n`SO$~_V@AGwdFZc34)Q*y?y zhDu`bom?e4czm)Ztnzf3?9TYg=C?9m@|d|IUsC5QX`D{ZQ;e^MxN^^cf{l?nErsV# zR#^{|5rsMU!DJ}>GZdY93QJExsxO%2D?5FKeDHpo9K~xm?PiG#vm&PoSnt|;4e}M8 zT0Wt!XPOFRMyldBoQH?=SmEH8A&A!RugGsqNHL0h#pp_!r1`X&JQyG7Yg|#9+;4WWZ-<2^+;p093)G}rdErVaTXijh`5uaSWwc?WB(M! z?~t*hamIbW#|zi|957EC|sSWG|Z*yQ&w z{o>bn>Oa0;(dSjw)ndK4|H{7%PWhpeeqJZ8Cz9fk3w1fE7iX7*I-Yt z_p|yDEdYT1FFG&tT;kW^Us~A{FYWt@U1~H)G)q+nBO<%ArFr zYEOROHoe>(RJRTpQ-$p-`jTrOF|!VPz0-d#s%mYSdFJrv>-Li?J27Wv5p7{5{4 zJa0U*6FqH%sCU|N-iJqG#UrJ5bSqCM&2PlS`Hk%DUcIF)wbcu9@0>f}G96V|ampdu z@9b8Lo6~@nDYY0rr3Qa^{~Orwa!<-YvL!amKp$b#YrSmaHyR+;zw(Z*;w@n*ze!Rz zIU{ep>ET$}j%9AFc#SKW)Bcu$2+yFEq>B?I7*vvlWSvTXojIr| zDIG;o1_4nh-oo*YLaf0o1ZM>(b&CAVC{eO*uIK_ zi&a!J#c3qiK;bQEslZg97l(mFA-21W$$?)}fB_s5$1c@b zJzRlk1ap;jkPK*)b~zacp^U&1P>i|EO9ZU4vzX?R4H>gbg+iO0%dBa%7%`<9O=GHf z?RO|{l;bxQNoD)Gic*yU9#=pYUBw?|vVBPj)Si-GWd#S=zFPY+We;cI>TKUY`?<

    nobr z@F5qt0u0$Gm7E}oB3Ns6XB;X!HdzabqJU*U>YkN8kB$P&nWs`wD17BSmbCmdpd2c{ zb)qD67^^JbD-v5E*BoHt`Jty^jGq@!IsK%>iAPh2%A?WPzT`6=gH8;NLXcO51(e%P z!jR@OF5_G}&Xmu;NU8pgxZ+JRej{mc6miRA>0E>Xf~_(vu5iXXm6htw28O55qkuH5 zbY6w((x&2IzfdgaF@6=+a^`f&1Pr3$$5$y(W30hQSYDEFOd*N;QO?^@fQ9xC;`>Uj z1C_c<%HxUZJuT)>SsNBC&y~t@_$+Cab;%Tb!fA~hVX>pE3m_z65MrVFg`v_igk*lM zY*Y|&ma^}7#K&7}<@}x}bLo85gdN~AHiMD^U5y3eu7|OT13rIpV{77k6v)qwU@(W+ z*OF%~4K0G3Sk4Bz%aDfgm9>#zmFfmHlEEHOkUAYmV{N<7X(diN2sk1o-N%Uj90))L zy3#k!@k2~h`CNpi%dT)Zge8ld`AW)!)!WO9hiv|3caow=VYrL^53&G?PO+fn z^C!=lC%`%{tz+=bU^h>2oli;(cHx{R<{Q!>!JC&wDON>VWW$(!^PMMR^qhV0)Hi;BovYVj=DSYDh&^ZG)f;|?7q0m^=3n-)ASd_D ze8tM%s=8Vq>s*9QQo z9@0?p=f;1(?ACkm&}Xj1m;?63NjF`G`ImnTs~&nBo$EG$vrxP6-1mNh=f3w7)D0ho zaR<-Elw%fP`bo!PpAVdc+NPm+aYU%@k1UxQ`0--pii8vy{* z-*Ft?_MN>F_TOMny18E6*nokqZtwjX$BgnuuHNvvsenx8c2GtD|IA1Uh`VlQ^(;WkQ@aY9?@S#MYMuKA4((P0nI_JH@f0GVZa5LEC0v&kg-%tXf5X5zsFlb3!t!J32qYY2v1sV64)QCh|LZ0DF#G8Z?MT>UJ~t)n{yVSdbc+44_+tv!63?Q2v<@Z(p^Pk3gBjpB7C;{6p8w)? zd|t_~iDq|lt~6!0)~~nk%)o7z9)pqTZhbhh{b@EvlaXvTOWM=bQ|4Kff!n?pFdMd}k%B&Rh(5iNfv zlGPePPi86W*m4dlHEl5+W3k1XP|6EV#ALmV!qhn+=a7s7C#0J9M?29hj{s3!(c*rS zf0e6sr1PQGF@|=ugbn&RTNGJ7;ta9zh^W4B@O?|^?U?}GZ*OLli-1K{Xv-j$B3u!`9_ON!UxPy4Y zh4XB1UYMcfz>N$%4n|kxV+3NQl34nSPEzVL?jDA=0i3=IHr!dA+abMp%l%%2Qv-%z zp|O{hn>b7W1%xCA*OT`SqZM63)?XB-VWAX!}5O9ze}oMcZ7y3i^{=6rdP zSwLR=&eCKgRyGm=s2evHAgl};JYpe60%5(TUa|93UNe5GpX!&1C#GsGE4l|=(Cqbz z(1-}9VT9RIqyG^^vxb3TGLTlZ=BzvFQN(E9{}9RR+G6Lku#_*y-x1~$H`%fJ#o$qa zcl?h1QYj{p$iB;$LzvuFAJrqdS^yOB--ZFXj|r-|y=i_jo~SMBT3`9Gis-0EL5Tyw zRQ_|vUf=7zIAZtps4&1nA#R+=*7H0PJ>1>L-?+m>(xE@)#Df5cHMb224uQ<#`SDNh z$L64(3NLVQbHE-;%gHD%T{TJLnMp}mc^?wYSL4?Ou0EpZ{&%cBGyVsUrruR0xC#Vj zAa#raw1}J_YlhQLXXZ#QiAg)Gap!Q>UCVZ$jPF0ZKmTTf%#JE(*>7SBaduK!VGn8` zfZ}BT{I7BjAP1Rl%r^4oTlO~u-NkGeTjD69t5Cjt^P)d=BxM)y2j8U4mh9T!izS?; z>90ZG9;kXFxE8@@dSBa{09FfF;Z#N*U|gdo(&HHCg#q0>C+jK0w3Umm0!35_j{nkv zyWcD*D|A7us#Da-3v$YMS1P2mGA%fNNq=8j0~>_#1c}pZUh2;2lLySb`tR_l+i0}J zy8+emm%cW5`h#=nMX13;yEd8SzptKov!{Q2X3}1WZET3)@()9Di_7=cUrSrO ze~J7?>_^|_C>xv7>7@W=iTK05D;5g0Df>S41XP=C@zQRAs>B0 zwkK7EDy#UBv0(L*pp8I#*lpJmE%v46UB*t_<|TtBs@_ZqbAxJ?tZ{N5XE z-a@pzx~`7L3PuW^JFS&0oci8l6yCEv(#8SnxBYcO=1j=cN2i(CXJjUgi51I}76bpy zZSrd&M(?{H8V(I>J{}G(fo-hf$7+qmE>j%JD31#0w|_Csv{h0X%dSn;7C1%S@jOw; zR#-xpJb#APet{6B4XoD#r6ly^h?5^qp%RKpo5NU7c|;M-6!~py0SPiyEk-4M4QC1{ zu#_gyK4|_)iDzwz4dk{;t4zB>ze+z^bt%-vTk^q{KGo~GGBt2Il&)EzI zN{8ox4KB$SY`{)QPs@8ejrDBSH-*`G=WeR2p@~b&-sScU+=X=86EE+K!!-r&^!8)5 zC=nT`Otu3FnnLP^YW-5sn$WPxD zH!xa~yIC~~8Uz_fPyyc5ecnmD`1(HE|3uJwLa&-VwgwWEmwXQ9j(v#4*oT;K{LayZ0`o10P`BCirB46-nZ)0E{NVpkB^|*EB8|x;1 zw>gczci4zD6Of=xA|+*%nv*NK^`qj>N1HQiJF0+pD4bA=fqX0Z{2Rmp1I15dK#n?~ z{&YcWho`p3loAToBmo|aY;W6{w&#%xh+7!6sx zsy6l=?ot2DLf3a=c9HxKCyFT;K5=a#ZttW4GiaB49*sU(+amv#(mW~SD7F8-ij?&`pWh`W(2 z1Fv?XVgx!@V=^X;!>@H7BYWC{tnqIG0xP}1tJRh_9{;+lD|(Nbo0BStf9s;fW$HxS z?=lmctCQ1;+`!qEPAo!%O73IQ~Wy%gMlem zHkT)iTg`hFf9C0o*o=*xrg)o3vDtL|XHvd}LDs|D#p-px`!dRzllR*{bTR>drgOJb zi?%)Ap8cY9xEHM`S#+hEa24mndC4Sp-2k|=TiYA|1dc&T4erBwgwUp^UivjZD!00e zl^(MQCI#)N_@AuC>(AK0#6y?!6?H}r`T zvzYn8<-pkMUK}~hr+f#P0&V+E#1<%Ao(nDEQi)I>GKF|J{hbql09~rD%ML+5;S+sNLA?(xApWj z=X&v+}|Pn^hV_kOka#PSG8_b7)d@t?Yu9+RNe9 z?|nmD{ypB)Z9JpTju`e}`Sv$A=v^yu&OkRg1i$60xDY-4M3EbXBQ1$o7iqrLY>uOz zglx*TO$_PDOg{Eo3hHq0&zqafS<#y=U?x&%m;GAHVS|E?QGM8@pF;L%H|3uO`%ABp`mJC&G&Hw zuQv<(?FnoHkVvl8AL;twi6GA;r(ubx>3_YOb3F0=)=aaJjoA#MpKDs{*nXGwX=n`d z;}1q?IoAPK)&%Le3rl%1bZ?ljg7WpSgHDtbo=f_3{roMoa^|`sjul=N^D#kvBYFRp zM3h4y7&cPuH}1Bz?WbDxCA6*o$56O^g16{LN+zl&Ql@5~8=^_tJ`mQsGZ&)jJ~W!ms`%nP@h{mO_|nCh7IpWVhG zt`{`FX*f@(Mi!LzzQ(||!pH=+TAX6C$>1Ldvs1|uvKZ*h zTc^C+mT#FS`U>va6!xkmMku^G_?F)k*`aazD_cB{-$N@?BtM;4T6Toj>6-riQX_Pd^qmqrI;e^f_=d}@&TM7JR!;)P)<_4=)$QlHkD1yj`Zz z-@`11(_-E6^1lX{(Gam+s=l7!7X|}_oc4)hr|sW=-Q(&!;82JYdS&}@?fPG$lHbpb z)LzXkz$Obp{SDB#zyGb%k^6(_YzK$MR!@q?$PA ze2D7oa<(~5=gJaNoV>*2jI@O9KX!FBlDx;s0{ibK01Km6kql8@pfncFa~#LNCnd26 zkxAqqFQ5Qcj0P4^j~@+|5?12Lcq% zFV*^j=UP^<@p+M%+<(Z1SFIEczh>u(vLYy#Md+C!um!*KMCRB}7wf;D;POrJtg!{d zF8h?V-t{Hm&g46BuHb7C-z)SEZz%sU;*?NX#QSwRLkeLEh98Z)1I6F)ur-yn}?gt9{cjfl*@W_qG{N=c_YXI^bqz$ zCXZUeP3)&SsiKmb<(!0#dz@!?Nvw+f+9)^HBjyinn3ty~A;il%G3j-A8E%yIALy1a zEw35+>Ky9xX5)w7YLx~rxYB*Ex}8RHHGU=H6Z>Ylfv4QUBD<8;B{Wl%+3&uGej!_J z(_8>^S;#C3=nsBBg~w9{NzqwFfUWE<4{7~x)maC-P980EsYtP!W7Vosbh{% zQ!S zF#3bbv|argJ4}`ULk3{Jhaw-QPQTe^q+-z6SGITd?Tm){n_O}68!VWbu+Fay9~Ap6 zjUq1yN^`5^lb8+a({>4%d>Y`?M)=j2;6Vt8_Edc5uUniY9Wf;POLr%O*C3|_qv!yyg_Ig@x*xqZVIS0nF`_NsF=BESuO zBWT}(xg-6ZrGKFS0zhMr7#8|x`V}%k{wk^`O^z87#qK2+3DMAZK4R=r{;sa0rTIjN zF+7o?&dBXvLwDw;Ba;KmO8kgwPkT@GaAz-_S-I~S-tsK-JO7&}!CX~OGhxhNWRS|PDiVRTSH5Vy9Sc!8Szbj`QF(fS_4_=$@*nl!R6sD%Q_p#E&jD9AX!>*+tU9+Mmdz{XSj66NWJjUmSmPWWGl1lNK|3{p0^dMc_8 zz@WU{2IwIcwT32C5i?iBwF|5dyFauetuV35yJDPpD^S=%9e^Ec~9TA9~ z(flvgja?QIm4rN}V{_ox$kA^iq6W4U<~;%c_n4fC&-le53#s?1pLn+!=$RbF6bcXO zb2wvnNX5NHIif zi64!-ar9sJjXV|J1VBVC);n^waMs#9zI+=Z`i8y3Aqi}Q0WLV*iAY1{qq`ba=ehI; zBVhC&0i+_NCdp&U8km|ZPl)kER&WL{92 zpg)qy&`q%>jJ~xw?Pho_w(wRh7ZF z5&&?!3xD-5dn0u88q+_86qhO+0R(Ed?#8xcSgn4qUYg%wFQsoMk zY<%eT^tJ3z_dd@>IKcOSr+Gf!y|h7H<3wXG;fCg}3%JT*ql=33bkU{GrPQ23ij}kQ zh2D4Qw2@hSZ2qt22fhs_zls?GQ&~acOvkKy@?g8FB|RxE%_9cCIT-C>6<3_PpYtms z`o`7oQDscP>NV{`aBB1Q<4PWXL`$CMus*JoH&kB~937`M_3}Gv(&U3eY;n6Qcw^L! z9jZtf?+siT37X`YXHj{&f3B*FI~WsBR}{Hg(26cKHQngDejw{nu!5YgXz9nDZ#6l} zsD6LSZmrOM@^K>CY%E5f>ZDmNeEf-&a-Dhyb;&R9)c&V}BF$0fw@DlSt(JTKXH`AF zKXd9uHbKnxma+d|#@+oEz~wtG=6y&e{wLn>RPyY)N#JS;iklX}g>g*w@c0=hz~6bx zjifQ-?-9B0`~TBi{cx@^|Wy|m}%%wSZGa(nkN zL!D_Z$mmmYVbT>4C`tt>^&VnSAw8&6R+$%`qk=o$_P(2RBFJ${ah+bcO$}w^fdfW} zX`(i=^wT0(uxl~?@1GxKWj-e75KDc*v7xiUDRzZx_U9zo@b0E=&!}rCD=O!G861iX zl#w>yVmd?r$Q6wFf=ff9HUC>v%s1Z4b-P&j!1|d1oV!2Myvy$7R2B>ZG=5v_yf!$q z>~b6D%HF&Ce3?y#D<0ZJ?#EjxzVCARr|#X|Hz-&c;=Z&og`M)?bbs;e>*Yy~EB3f& zdjuPp?x(>mj0ke4di)peG~LXB02-{`aXwZg5C*D{EvPQS<}s^{*gJgBhOp6<4sW;m zYe?%-Ax=s!nsVL_a#xm}E!1%Xx&Im{b&tA+E4QASXI+hRv3CMNAEUtVBX#?jaP3U@x5MAZ`qm$p&OhnVwzYY_b7nJ^s!e?em?2qOZ zo?=RCN3*{IkXSMQZ(=4*}hVT=Z{DdOn z^YXPGaI8Ls$sOEttg7kAH0i37I~gFTfdf|xJZF8Vz7u5K4Yg;9itwEEfB2RSw!Knb z-(+7_J$;Vrk7VK%R0wN0AQ*=ROL0LL?jK659{2^{rw%0iWy+Z!>`M?QYJ}N4Hs+6E zOw9C$SV7N>GD6307-vgk*l?2pOb< zmz@~vfZd~kkvHCUsmo=zuBH|$jF#jq_I9FA8&*ChoSJk~p4ois`i?uWHU7nc!%af+ zn}ryn!;9e*f#AX;56;&M%|@#QDgek_zp4^c)uXse>`9L7dk@GWHfg(!NB$q)*5#47 z&ZPXr6eqM9IT*d3vT;wgtqb`7EC6^lm6{2!v8SL&9ea=GrM2P0{5;9@#0>TY<4=L5 zNy<_5rQo$2V(!*7z3-jwCIb^Q-ESkKW~c6LWz*ttemrbVi~nrb+ejf!ykS9CK(D(0 z^lMxV+TV2UGY!`p`9&U7ZJH-S>MU4uNg+Kk0~2I763mQ+!`k$hsoZ)z1T?5W3RnzR zizj2^`*e$UR{z~>-h`KgQBuX79bWAnEkq=~Addl0c{5gkquXBXMTfobML3tLCNW|+ zUWLtjPv5uNfs5~bdT*w#duNZ7ZcV!3iY$V@O%&EMjt*BbZx?tBW9u`H+wl5vPwwkG z)KoMmk;7Dv41r9v3u0%yrx_PlnY`Ss-Va5z`J%q-$%xIJyHw8g1C;$B^oBPjjxPU^2v?x$1)e#+cJgZ7>aiXodimxaxp2~UXU zM+Wkm^{@^8K1R3pyyk}PB@nEPEgU;)XZ8!VzO7rnt0ws$KYOEcGPmDTQQh20hZL^5 zg)_VWg*gVMV%^fakc3Rl)U3~_b49mbwJr&hDA}TR6bS5+`ri(H@j99+w>>FZs`zHD zaXv@-LJ=)hcTS}g+S#D~qoSsDwa2MbEfqWVl|2<`@gvg-W^m8>UZEssyYFUQZ7Onv z`n4t=(P@Td#?WB8>IL`3P```U#-$2?dr%)m-wTLi7qsr1}l3&H$; z{~x4tyGA2*f)hwihk4@zYCPMY+8TjMid03wXvQy}4*ZK`&`gBcyQYat`Ae9hHYP0> zg$$+T1i((MApeAAfvzCg`J~mL$HZ9kyhEV+pjQ+~Jk4@)zopfk2K056c>9Qf>F|T5 z`u)9ZV5N;iYc^e&vaiW>jQ>H05Yd^M%|d#sCR?ebv_;G1wrFi1a>V<)7^rFWSolJ+(dbxLJ~zkBVKoGqp==t6t9l zB2+W(1f3Eps^9fK0+qe{)<8X8)CL{@{=eTcT zvSAxu7{)%LZ}(7yhukB!F+?aJGT%crri336omak;abA3db@zUH6S*mDgxetaAJ3xa zuCLz-smwaL=pWD4G;U7>cX#$C6{>^iP98Sn_Lpyrl)WDJfHp^wYPnZ&L9C*#&o3`S z$eto7JKzZSX)+U;h|c}H%PAtTl6Wh^MEmv4hk=d$alxPOUTro3A}&by8LEC z{(0c}hT6dIkJbHTy@|AV>mG)nDRzg)h&6W@a26(*Ygut4v3K_2;G3rhnxq50(7Il> z(dNp?MRVzwuQjKMs-MT;#hhn9K23+k2Dwpdv)VL+@N9GE)k-F-D4ypfZAx+&nV1?P zo4r4g@ss?GnO(;il({2wWe9Z0|7rX9-L2uEM&~iHi*E;BBSCG9$7_d4b5Vy{RPEv7 z@qqVf%8&qf7tnL~Ol6sB74iAU{2)~H<+TBdMcZSco=g#mgt^fYX-q@Hv~^>liw&n?N5|_wZ5`m zgzwpV5o0JoWpEi@DVXW8RR}9deB!A28g_Ass9f{F>|tnCHUXR%zU2^PodvYE zNugp;%t$B0B%fZgEp-(hB?R~c>QGDsv}!13fs0fzv-^}S%Pa=JD%!fNs*%OSyO?C0 z4fSbCbT2sfN@Ie693o1Xd(-~9I=8aO)9);dYfW_38OVMN-7{&O%fhdac`oS@BV>Ku97SZ$-<+xO%WGfJmfB&G4Xl1r! z3nd#?G+xt)WSJk1&*OW9=Z{WkH06*NZlfz<&g7xe50#8%0~>w)D}NObt0$6bNn?E6 z3?zLk8G#=~+7OUqG&gQ2h%+CE+%HeEFtmq%y;%Rw-?n+_2DiWadjXSiwFf>a2 zh-Siv!>A&d?_d=#Ah4FFVgNggT0tS5IhZD_q@3xN1ygn}3dfbDy2V~+K4t-6@S-T= z20*qzmbBW}1L2^cGV9OGO^1%PJ+#)+@F{Ssu}UCErR#Paj)TpLaz$oD^qYUpUnMC&S{v5L+Bgwxztw! z1UiRDWj8^#WWEMCFYX?R&jbPy>C|g}h&=rtO@>$yX=yuthySX{ocrt&ME+*O1u2)M z{;+X8F<5pzo@%%~r@2hq_yj(^pQz6J)Dn?qTpu0?3xXh#B_Fc2J1SsYMeTy)lJtL% zCojZIG+-y|tnldR`nkJ1&(`XJl-r}kL@-^@t;UieskHlEuvTm?u?P(f+EBsd5cb*8 zU-l^BsY(5&5MO%Kyfp6DCghKb>_75R36K^0pK7E zmPwYxVoyHa`im)}3%Fp@py!PFVF^<;`kiS;3T)T{kqiJJ>E(xq#B{zqNS|i}N~Nhr z-4?sdn;J{H3=71(s#>{brzhpnSqhlw(MLyIAb`6zU_ut-ZXkC4R6OUumEZCsM(cFc z3QxC}byM~I74x*~?zFd=puas3QKjAFq)n^>xFIaJy;?oTv_LRV00|Q%boS6hdt3HV zxaaIaqV;R(Cx%%Qml_DdCldvYf#vTbjz4m!+3a8at9v)_@)z+f++%?ZsU5I5S3hGe;is3d)v*9>kdmg!@sS=@T4Dsx1wqr9lmB~gSTw8 z8@Xx)3|W5sqSpru)Au2iN^XdXLb=m+@agT%bAcUuTWX;H$VtiDQ@V=v7AjGAWpy!w z*cm~(VY}z$^V!p(hx?ce(Tp+Z9uw!C3NYAl6P{YAzcU-Vr4A)vN$ zlTr26dvYsBY$ISz`NWrNza9|>{~rH@Euao78G&a08PrFCsXy{UL`#HeVC5*SYYvLM zj7KnVY>Em1t)ezl9fIV~kE0F^o^8KcctwOqr6DGqL8wXnkKQeAja(uOSagraOPE3xL0G zyF>_wCCb2r^^pm0=gI^TMW{jXZ(4cP&SK3E{qtCc28p;+vC=Yh`aDkH^}i@e38x#C ztpd7`kK;Jm8HQCays-v<^h=WyCsnmP_k+6IDkH%)PuSySeL(M?!WzsJHLT;JHSeyV zU=(hNM&;+w$>-VR8eA}6b<1YaPFUxcf2N`SisxvCuY3!r`ORmZEbA{!Oth=FE|?=D zuI~7AjzJnB0OCqbH+HK6`8Rp5_J+-to`5px^W-?=W{nD|6Wf zidFP=fs8~qy}p?or92B`iP%?dE|PvYEfSgCQkd|q(fmYy(V;#(6X^4YHslf?-6qPB9(ZyYo;c)c^dqJtA! zYpU4+B(3kwAjP09H)IO=>97E*-6wrwaWl-9m6G6G&ms84n}B=pIQ=TIVAQkhhA6Er z01MQY7n-r{Lk3`{E8pq2cC>49y5f)KuGm4V%G`1EUdM#CU$+)#oUGtEsB5vxfg*~L zFABSUzul#QEx1?jJjt^Epvc%6ltAVf`7b-VQ3_Blll9aF>|7~NB@JF@@%HLyxyi<| zzb~O_#GT|=0TMr_O4AkcirFSV7eeiAIS(>UgrC|S(oW2GIvzXD3Ff*Qks$Dc2-|oZ zl5=0ENLE?u(q=ckC|IcPMrF|6FTxc(;3<|d60IKx3{t3j_JT5SPJjbNE1kk21&^l6bV+FIB5;udWh}VE>%L=$E*%Q?%BHwpM1LV z38eda6UhgZshMIHGg4Yz|Cu$Or{y!I6-U$MO~B!z!-6E)K>Gbh_43gSzdKhmMyFFV00t$A~Zi{O`*j6m!vUVl(f4zqKv@PnLq(GX89HkTqE(}5n z8+5lWCTNNy+#mKV%)v@WhIe;lCTE3@kv3hsm^d#EHsO(d4ZKduu~HTS>rAo!4;?3& zsIpM`l5-VsMycD29b{(K9%fy)Ym$?4S2!O~$E{sdUY{J#T`*JvP zCh?k7$iSsb4T`?zf10RZCeWAY(BiLvCLm42U5iM{yzh z!cDJ4ACvI78w^tu-pG(w~w&V?aO>Cx9!UuSUx|)Hb0$5%~&{ORX8yc z_V&M?>b%!iQ6e*I zn%7!MJC{Wxam)C!l28+n@Gq^V`L(#OdFn?vDf{k6c+s< zpXbV`&LUmfBtp7zQ6gchO9;`vg=ebWQNst#Jb@Yym1)?^M^R?DnpH32XRVqh!&D10F+!$tj9Ph_G)vjEEHYq#Jr-{MI`fl zsaGCEPSW@UKERjJ_{83K7hUbK%Lr{%>H^mVZheqz+6m0HEeYs5o@m%)T6;TNA22g! z$S(MImH=cl^pPNfE1tCyjYEE#I|b@eQ;@1TH;CR>y*v213btgdky=Jle&C}PAvMIj z{QHnNfkZfoCgEzEUchlQ2>?0p?Q$&CTNWoCrCq8{?o5<4lj_15PKz8>ib45_SN ztFe*N$5Q6N;-bH0*8TH5frfy}8Fd3)(wMAcCaO=HwwPM+1l?!@-xTJ4o?xzCyv}6a znttR=H)tv;KT}Hw%-Nb7*sE+Xja!a1H;K$1FiK-BY`6+}9<(Qg(TpMUV z8zP^TV7{gEJgJG7=PnX6W(mFBsfM?bX`}}V@|jHG4^|l#w(F;9Cdy~hc<{{XUSm-+ zwajLwZ-+Xa#xXM8ml0Of=~TQ22p;$}I7-KGWQJuamoH3A9v@0PzqNL({XFq(s#{FP z6e!&HM^7ThlGCtbyHR;0eXCg{khsF%#~w*NUC+FxVaM`YN^T_L|68yj&NAAf_g!o3 zmQJCYh#XX8WM-@LWGx;W@)9TsQ`%}-XtC8*S5%FMkx?v6--4Oh6toyI7HC%Zt18g~ zttp->^;=XSkRDXMg4>ced7acVYyXr#r++DPm733PHt##zCYjI3=9J68%>uFCGebWB z39L2qBUvn-YxDjPW>@F+4%JLgZtFX>dX1#T$GZaYm4Bz|lUoywM1hvljkWKatwtH( z>B&|@+FSs>FYX)FTP?q1_NL*wON_4pD@7%t4Q5=OU3oL>OyRU@y16jv`&Lh(yQoHH zmf;se8ge$PWX41$HM3R( zN5VLEFGLbrx74*#sbUErXfinktwEfmHfuSY5T*({K1;hMM++5H0>;~E^vbX3-ah2N2q0BCB~2B@4K8%x zt~a{*G;ycrtvhvhz6Huj*F>)d!0uvauZrUwqt6v+lc|`$J~($JR+;mm9b9-X@Fj5y z&4^6v?-m*n#skS5C1v!s29t!SV=6BA4$P5TKymewKc4aR;SCJ^S5Whx$#vF<`18h9 z0`AD6#S#NwiV1<89tCpSd|@IXvyQWw9|kdAob$;&0h}%Yzhz%B9vK5QJY^Lq-!mG_ z97(R>x?R~HtOlEa91WB0=A^Uoy6DE&PYhYztz^n+?D(q}Z!JZ@*U_L6?8V2fKoUp* zU^p3`X7Xq1hWnE&;Y}FJClTNxaMPme1Y4y|)j7JrRFo>4gJTSV9vkRP6bELB?*s5S1G?EO68rw{0Ypt_>S&+&m zuP#7gl?IyfcD&5KS@*QMrYfu7wYt4JhD+9N!| zJGrj0Ml>;*y^Td5ZGw(m%VNV}DFmw~n%|st@TrlpQxpfI*JeXJ&H9Z3Rv*hL($i66 z2Krtt33D7+#D)W!SZdj>_?pDQ6%(MjudQ4w%>}n};|%r2)Kn~(?{;!?7)!*RS`X#_ zmCaiwFx#??zfJ1-n+Uj|m&xDsX+MZW7LQ*#+g8IHajlRm5-i-6$oc>l%s;+OPU@+g z4^OV1&Kb+i*_+Fv;w$w5ex;IRb6x3CY;^<{O6Dn51r2%$%@zoQx@|;xKo}wn6HeWW zSjbKi`M%t2MJ*P%&K%|zB@ixEjD5|&mo{$?Qi4|nu4d|MX0WiVYR@-s@|yo+UT~A( zV#yK|V6;HgNz@W$5-~^vL0Ox3M~N{HymNV;V?t|Y^ySs}bsrn+ zldH3c6uPYsK2$jBVa-&ek$mMcPXKhXZ^Zq`v^5&~O~2@TgWSR@2iE5OdtU^slDn=D z3?hF`opaEUo1C_P2;Ve1EgCK|QNO!zpi5~WjWMlD>SxmKkRzcfKQ@9JL=y%MPd zVcQdhbPR_Te2!eM_{ZW;n6WjP&XomnQi96+KdR7}H;x(T-Hyr>zaSDQdm~A&;X)#0 zQ0dQZe;-kl1}lG~a2<>En(nL%Lz}^xfraDNZB(*VU1mFP2{AXxRos3xh*-CuU5kTE z3Qjht`X?5)eX#mCP#X3KAS${;ipfrtRgB6NS*B~drN1IIHeTQ4v;Gp9kv??fB}z|V zE$1C6=p;>L_7_UmOEB<`70~Pf5^_Vz!mOPJ#lE!baIq|znOO_F753J9g}chUNOq@< zq-fKOXn1d+7LYmg%Q}gat|94|Y3S2xn@gItUK|ICtywnFbRuW9DUnypp9U)kNqU-_ zN|a-h)enYYYp{EEaau`!^k3eYlnXe(I#f%@t>%~LU!RI}JpNIbx!fLQPF0ZKgp^>L-t8*&6D$wqQ>jJ_@C+vU;hac zr)M1v5NZ#w&?(C#+Fji=OT;c={Hh{pL#LHUceFTlz+#xMz&1V&UUuCVaS(G4v<)%P z{Noa54>I$|2Y5`8?d$&g{f=w6L!0y`^HLY91){A7sz3gN%`#V)U?0#|TBcXv{_vA$ zT_%E{SQsQva#|W}ti6r~&$SV`NvCUxuUt((AscH??2iks6AP@e(>+0s!uBAks>(^F zo5L^iYT{tni%EikgJEFX(kUgz3bptXGOIzkBQ~{Ndr++gT^q<%_;AX5z?aZ1{RL%A zc^6)oq`4&pOMG6T4}IKjLN**YJfBf}<#BxsErcIMK|iM(XEKMH(}4@{JZZOe*`Hf; z>K;KaW4>E2|~VJ(U!Wv$?8z#G~o)y`tp+$mkW#or)W zz9Z2ml|#IP!h8xovsEleqdDjPs`})jOhTBw)3*g{@LP2sc>o|QbSRJ-t!=7Hk5v4&!Z8+Ll|3two>Dq zVf~ERTY{&MM`3Lnn7;0GxECqrw5CyAgtxDB>TZ$_+Pfgaty_G_fX{FeLI)SS>P6g(i6xl4-?Z4^39u^0 z_>s@$BJ@53?)%62_d&!4+=X5+A_Wq#tn~+N$!uGf2(f0c_t}fHm~~k z)zZ9<(%s@k-B4Lq@|*E%<@2uLzUf`brBBKvMDcM)qLySacfrhqw<=^}m^j!SsIhPQ zq6a58zhj4q{gkZf)1Wa{ub=wbX617nHXn4tL5y72j$b#N^o$1v-P?xtNa z&UU4eqq^#%RO)gBtb)~$wda$SHjh!OAQf|r-;}KU&Lg5E0Eir2afpJ9Eq6MBUu!VS z#i_ARPzg0U%hMO|g;DDWwEKLVD_w3e8@wJP*wq@p)=B!7xmsR$=lxZ*(h@-r^;;;J zLOw8j>6|LrC*@3`Ed{e~I*m?K%bcAXSzRVc+{$V6dg5$E=}KuKn;ij}kwoJ+!3PD^cB>{A)2&#N$ve<@d{mOx>{7+&2}IJRK0kIGU{W(hRGV}Dst>di z8ej9MV5*bEAlq~0Sa8mC4uL)2Nc|sKZynX<_Jj-91zKo}6+gHWv^W$f?mc~j>Wxcb42Tn5)?E4m)l>3LepLC67M_LYOvk~YtWu9uK zSy;6aa6TS2;@ur#rInPiuQp*|wlP~L|21}88zOIQrEx`%Q1?8Eu|5!tmlUJ#RW*P^ zV9Pyv1MWdWo!d__?o0+7S*vSD$t>81K?oM7wKGJ4kPaKGd&9dBOH=?4$QsCi@QtPp z8Y$WE|7-G(r(l}{N+p|+ldAj(n<&wEZvaDnA+!D5OkjZ6mO0Gg=B0RyACl50JK+>6>4-K?f8=oSFWpX_ib zmHM=9ISfxhnMf4WXydYH-6omnV4!KgjYvS+EUrjDe6DrfD%_c}O9~l(25z5m*>zgA z%m0C&UNLe=MCNHjyccg{$fiT9rYtBWUI=b>!+9O%hskXUYFL!Uc>~OC}|8=A|rHt<+!lqyF*eOIg|Y2?@jq0v*S!4m*$ioxYy@cjc1>Q z@edtCVU}c^@d6tO$;(Fs`z*tfeU3Sj_UYjh7`sSrDaPX5JuGVAE{df3zI-K5Dkf5( z)gIng|elPiG5w6$gN zg+8cfIp=*-PRS(6Ht?mcy_n@OGL1MQNz9DXhrD|LBN+r2`xVpCag3RqWCb zmk(ZvWg(6zkkBCI<899;BE60C@y)Us!w*O*uh>di=$Coc?JYts_N=E_k&B{k?9leo z+Xbunn*!NCS%*<8r!t$o?-_FrQww(97%3?#tcPXayN+CC8EK+yi0a3*<%#zbd(f#f zj9}HAXqPXgkzhqkmBdMG=Mg8(`$ouWkvdlR+OxtQO2vIK=9eIBs|8H{hdok7(o8mR zp9rcv?8`v(?lv|IU>fiUa)ZtFHT$w8=g*m6GeHO`$u?rAIP3_0sPWkui=3oBeXvi^ z^AA-Pr5)u~7=!A~qmN$SRwg4o5bjfBSP7$AOZG9I@{E-)u+@3FC9yjT#$VD|Z@+x( zq>hv*kgUakwfxm;JyxdNuLO_A_Z3jsBGS!lw5Lbbf2rX|WX& z(drcO2$dhmk)KG7Jwp4KX^}r!c(x|@JBwY4PFjslc4Xx+_qQwS_@t<_k>LNUz9xP5vbV28@%Zczybpg~pJ17QEL=*4E>yc}6|w2Y%RY7Wk@x*B9Ev{=jZ;Q@_>|npleRgv>rTp+ z*Z#=4D<1ueV9NU+oWNGq_5Md2b!m)fnN+n&~y3mEuA88VPiXq{Kd*7<$d6$ z|GoAlC5bIEW zJm&o$RoXBD0$4$7r7?}3mexA)$MM$mocuNSZwpDQ3ImX7JLGY`u4V#P{)i$c7XE?q zKx+|%nG|c#p!fT`*!>@{B}flnO0Mkf%6bV?WlWWM967=RHb)t(i>M>@Wz1R#s>ap6}8&KUxFbp5JT zzYs-aX{c$qQ^jy~|K5vjHuVcy3LPS=7u31|b_bV^XSS~6ENem^a52LQhTLh*uY1ss zk%%dIp09~@(5`<w= zsV9219DfEV`6^;J8}9Meskeceh^}e}eRZpC96CQ`0S4%`D^?<_FSzS{DdZX$>&J}U zHx@ee2VTJp6M_Vyj4Fv(^|MY^qp`%xqY0X2c+z6=ciKKO#hc$?tluLS>sW|V&o#l$ zFs`S_Qjr)iaVIj=FkJ@<+6&OgEMg+ULjn}!4cUr#)P6+l5h+i|WI!QiA?+X+q(n)oZwO(8sYv6NL3;w3LsD1 zvJ)J<;EakVQyY;eT1UR#$>dTwit}%>hjk-ETgRfH&M*ePl4!MF19xHjm6LyXAGohx zW}9g#gwdg|=>{7^@#ivEcvK%K%+jezXBd^l3WP`g690#M@%dFFC&~GItwWoGXh|n= ze{Wmkk1ucfYnmEwmoZoKfriI2$?IKNIgUi_Tk6RM?@`7ZlDBVDB{Xt9U5`3#?BuBcTm2JE!ir2$U?(Rn_@!OV zj?1kjv(6$SO3NSe9qnA0AJ654Yys#k4&RYROm5HL1?_XeVRwyT9d8H66$hexKUx}w zUh~$35Ems$HR4Su)N@dkC8(@AUe%jtZrF+(JHHA+&0yoG=iXlGU9t#DuC#XyH zH8?A_R+Ga5*y+*po za?r+_*4n0-b1)%3u2~l+HTyQ5-%cYCW6_xzYu4+oOx4(BfnF1G^~>1_N8wk@ToZ+u z#~;_smct(VEn=L$1&-CZeXPu?b;9Y(ee!Kpw%(3XY9g2;Qzgxp6uNoyRAu2*o5dub z)OzYX7WbF(!BVz*L=#Hw(y1@Un)|1lbHvtHC5!|@RMau$uO=Te%mL;k56AW09(!a* z#iULROIyX(v9d^55g)N}0yLrc&{}#j0)mZfk7$K--I)RJ*+ar>NoLYtNv-T;_jK(L zumFo#dLg1$S+x4|kDME&`*5ezL(`=rX^1V_pmM^^)Gzvc^Crcjwl?R6fb@Vhm=UN!)0pi@?B0d*P)}d`O6Yl>0vEL?o0cMTVG2ib|oymUOzSPzF<;T zR(+!(`dLYOmS7!)o{=qkf5coYepU=+va$o%jib_>5Hu;N-jzr(miD+~8$d!7GTk`} z44jCqjbVWccu`(@gZGY`{pQX>7q6OED@(*`vevop#0FL_mG#_SV0ho1@{5~$v%>T4 z{g1fd4>M$9RuaOZRd-upOn9YcRecBo%_I>**UChKdIF@K7nP2cCcP6CfUQyfk@}v) z4IR?O%b25^CkTJyvUO|>s3myUgla;DzTf2_AR#R5X{tYBVxEi3PPHXMjS_J6g-z@f zKy31FR$Yti4A^N=)BHk+6%g}RAYBoghK?@ksT`)r6H`cl0v?&zE5W?fYO2qJXJG^_ zJ}ZK|8ztZhykyiE-Rc9~56g5<%^AHhcR#ME6;Sz+QruJ!%{LPfx^P1&Kg*JzmRqs3 za);Iy&Rh#03xU!2)(bryX0BvKIB!O9*4&>_nzIWraVyp@)Mh@+T)v3K$x9U1oGR!S zvi6gRJ85L=hvqL(c4!g3Lq688G$(3t6S%SDKwI=0qq9o2x`xVI*pe?t{NXNSnu7`6 zlo!S&e^e`A$QnwlLCf3248iZer)y_k?|r}2M{(q(JvAgOhv^r!m&FFHfi>+LetS?+ zsKl<@3Z@gUA?m9ARjFnt$GJv*TdfN-xHO$t2Eo=mtTS1JSF_aLO8@X@hwozyr04fC z#NTyfS~zDxy%)t{+m_X|F}v`?Z&_LcX9QfV`b|qLU|pvS`*#&EZaQ$vVG&dF{E^49 zPq~u%m2^OW69X}`cA5~{9awI!T%kXD>X$Su=b%Mb5#0@S7-O8vo%c>V@kGg|&py{$l*`@%5?YbLBAL|vPFWj1E*A;} zU;gn_PSJ0iJU8v=S(L~oB>nz;AQ7@*H60tb31_opQSVy6Huj{Iw{P}wiK>U2Wa*f; z2y937NCfDK&j9T;%TX*?Ow!O+#jGx%{)qz7Fm}2uBZZ(^m&ph;T+l%TAtSz4uqyRS011Hldm<-5O zveC;O$HD{nnMdb@5x%4A%YAHUPJ-f1y6j)>_2h!CJvbyZ$Wlt7mu&q`$UZk?u}aeY zx*shzi3x8&S$5RWmMSiy!5EC4+hRkGurjM83n ztGS`2X~acp4|B7oDxf#Yc8sQ4_(o$i=o)cjeW3{T{=U=O@QP}~&L;Dodd+<^=x8)- zR*S#p%s3HMj36y;LqESaf`8PlDbBq-<*wd0wMFGK6?hiHtjQe-!Yh9B+`lo9>T=3$BiX`S8Ksk7@Ci8 zn$w_-VUp^uuBK~J1UYr`kNS_dw3*?uyfKQyz<4o&V9F*j|C^b}F4-rEW9 z{W*=zkaPqDp8Sv^-)B{0s*6Kv@MFb6^rjH5z8S;W&@%_7b8TQkImZ`GzP-A4TRkG! z3`p~Ei@WzM^i{SoWhT;Mfbf-Pya4=xA}a%hwenF?-now#%_UrLp#c95Hs2>M|&@-Oh+GAN$%IK zkAxGwa8OzWq*GQVVlUKC0ME$qJDmpBJtOH6wTzV`M?;YulB9VBF{@8(5%XRp_ zdfEJjW=O#~D(pSx*g`WhV0z&Jlc*-+KWG3GnoBCa!cMk4b~TP^bE^j^lH5_v0X3)6 zW$N}=mM(%YI4dG2QvGlSS=*RD~;M!7jxlckxQ@nwk>d!X}@}?8s4=|DhNKaP;REDao9e7$4NXd442O1}O`0@4_n^(r1*xd|x*p2|pMAN!Rkvg7&g^aj$! z|L7d~s?~-hh4FpDKmeCmUbzpall$8>Zc#9{T=>VTbQ!c*0(qSD@oNYi|HGL-j_7c+ z_(3BUcNEf`dmf$^JWOh-p;&14>dV3{MZ$pZ$YmNfmqHWQ-Q`hAe+3Ua65MloJWY@r zBv7BnAN=eEL5xijbx!4ffHW6FXjI zH4g76{%o*T4l6nkbz~P_5U0O5x+JMR^cY(x#rVWZo+Ck!OOZ4}y4Q@G)-xMaQcQ7Y zUiyva(Vt5#Cf}~l>YAE9B&=zPzc-8wA}9P@CEeun#`pAMuaSz!V_dYfwoR{(EJ1X? zrz110gASt0k}Sj6$+)vU;WpA6ZZP17)~~a-9u5fN)Mp*sMuHq2o^e3WO&blUgUKJ4 zd({6hEZL*OBHkYsO~g#Rx2sEwbiYlh@SD_Zul@J*j~Foq`iv%ebWQxFR{xn20o?Yn zLq%(iIWL=St(n%SXJ%=N_*6#o_T|v-e3@Ri-nh^X3B%*y)wCIhDVb&6o!>R?9<}sO z*Pr+-OIKyH;ni3@UEd-W`Tevz&@4_G(mTEt8x;!e6%HQXw@vsv}+1|5GdBY{-# zt@&%xIP`9QiIrZI&7y|5mYe%V_8G5;9UH<|qxWnae;330o{iNW?K)o#K1J@{9vxFd zu9YRDY!Htxe zhWRQ#6BZx*?#O1Jt-%m+O3GZWrke>*8|j#(?Hc7O7I>f!!MDrS+rcx(Rk0BHa=Ogs zC}QYD*{`y!9S)${LkDq(u}HBZQV;M%RlTN@+|TKLA@a@Fq}lh%v4B3EHPg$>d8Wn6 z;}ItJN=0+)HAh=H!S`c>a`_nwlaK4Zb5AiU;|d@1^TfoqsyQ0?OVYQzp{R9ymZ^U@ zQTR-wLEsl^HWc0< zf;rDmk@CCr*ToQ!z_NjIKf=fH`LjXnY>IIYK}VJQkjwULiNV^X>`f0Fzs4UAIJY(` zDE4z-K}^L}dmqt@mx2206;Y-v#64BdQ;7s$>u$>{ccZw;-@g-N^$Sf*Dz9>%lLP5- z*33m9CvKXFd)i+JldyC2_u*Qc`V(L7lg5S&3{7#eKZ$S3=|GV5-g{|Nq-VWa#nf`e z*e+Z~=qDvphUpb~>h#<(F|c$+Qy4HnQ{KKOyF}H16ugYFas-NZd_ivguktsk(ga z;`%H%{WeOd9^I!Y{!3#v5WsZNgVP$ODN1!5Z9B+7o%I+eIZr8|FQIrQ?$xBIYuP8C zl^TrZw|U}3;z=NAWwCGg;{{~|ckcwU?ayVs#B}rK1-W3OEQQC`A+Q|Qc4@k3V_2{( z+xrv!@o>9!z=hI`kaRC$!^4_MTOLD9?ma^)9^x1CkqF<=_|=uYp-^gRJcI{@v&3=7 zNcuJY_0HZ%6OJXVO!Bisu|y@S0lKYw>N2#3pE;J72K}&@tA0ia;yocX&}_G(H`)kq zC?C+Fu$w{}m-rmNvW#Y_QyER--EF$LFpjU-8e6B@3~K@!mrv!B40OhMSg<)&TzESK zJ>u>EsI*3NiKZSni^DgfX}23IUdd8yDx~peK{?5b<#}qkk3D$9`lj_&E2EHF4>egR zHdC9iMnZpdOMRc~uKV@DB@2(lE0`XuN`#>x9PbcloRq-zg~qQjh9GA^V3bQtJ&6So z{+JFOMeCP6Ne&ZaabZBEyI&F=+Fy>ZZ|C(5e{{^iqDhi&UgISIoT6;qgG1;FdMLK&Nv4o_Je*Mhtpi?D!NB)DJ?Q2~c^B%9>)h_fE|ll)@5 z_CviHO2_I!G0QTZnNk1}IEJ;({yyRRsSr^`qTlvlTxm;pi`y@E?j(kS)c4}mc1Lqc zSfvXIg0L0Q!WHrA4@>1#qfJZv;`mUW5K_j0;T85Q%6UA1f5u-ASjI|19jgZylZ-9t zFQrH1X&T=Ux^HDC;#T{9dH*)Fj4Krh;Ul)k#79-N3MgF)OZR*X@j+=b5)i&iHJQ#x zL={3k4ea`=LoIuWAZdyiIt~4FPT+n*X5)#k<~DTmYc^=O@8)BFFb}k&ITk5_tnHQ97&dTm+dLracbk5@ z+kr8~%bc#5V%KYt8N7TN!hKn zN?t&i26Kz*rml&wKyMsRJy@VP(tdZ}O3cpn)C%oAM(a#^I1aB0auRKT%-DYWs0^V< z%(Yul>8u_dM9MlCLtj;rVj*U-=@hEbGQc6)@RRD3RiyLParIVLd-=~XT*OUe7ht3Z za)UK#$R;$Q6F6;)#nA>}VV-bLVVK?-i+{!K;m;NKC%TCn-V5$4Skb9Da#0_A&&&8I z<}@b0zl6e$8Cz7Z(A<10Ra0l4(#ao~UnIn%2=J;tJ)Yo7M{fhJ8VNdOF-qFsckR`x zWf5F|JoDpK%msxT z>gp%X>>m05;Q}1R^E^eI&~j3^?Yak$504y1lz*7gA<`&s`@U01?`KChT7&#YjqQ~M zo~=9=_#IL~kBZM77MXFtW~R)`^wYBZm9>C^KphCX1zy`by0i7LSVv4X7VX!v-%F_q zWH%>HTQ17^YRq7M{0WPYixH+yXXSnut+=SYS!BjpE;>v>WZo1RwEq2C3g3N_Zz)Ex zO7$DhKr1?U)ijM50YT;Vr~@L1Od*A~wW~{w-_Hr;h@<^KcU9Jwe3*G(j8EMzZcJ08 zQVp2IU()}U>|(w0*|f#$&T5gN=K?~czlibWR~VzyT(<2ww?}i#06d;g(L(CtZ-D}U z&BJPzJunJKmUIWL`>VRG8pAlNyd0{#@RBAjk7ISc?j%@uvCNS^`R7e~&HVl#-G_Pi zH%t$BgOX0>K;IAv@sX@AYZM%NNW&?Ryu}%EY~f`S~Xpk88}f zpjslHHP*UBwcS=@RG+%_bn}SETI=n*(`(vbR?A2It+)7LAK6_VIamLzixTrm58#T5*$rP;a0I-l=A?QjB3IOi-c zlddoI*=G(TKAOVUjZY~4Jo>0)X`xi_uT1}t5zB?NdDR@MemCQO>ok1(G5kh zv0pI(+lL;L?-AT^;ni)V2DM>`{1kbQLXl5=xBKl=tUeRd;AGW9g{nba^%VMGTLoX4 zP2t4B7)-6@!u>X%qngz#QbRj&$xNqdVPM7Y!RpDX=5n)JK0&yT?_=!n_l|4sB{$@y z5hJ0;&WkjZotgp93(dR|S`*qh#We5Cj}bX#st8<8fuv*x&y9y!&)qJDU;6xeMc3tn z&EzJsY2ON#$lj6)YKf>|>aoMgYjl;i33;0H19cIvw0$4N71Yt_^x9hiJ&DgM$a(ph z5@N%}LtHDVR(67=ipp~^5q)*cGiivavA4GUN4$-mb`^Wz3Ws~5f6gS%h?S4R=uH=IU)4Eq#|wQoBWV!aC(JBz9VijbR9NjnuC0=Z}SupCqKT6^e5h zZ024^c`@r0VNT{x1q*_qX&5XdT6PV@BJ~GQ@-P9Hsn6_S2c)3rcAFS-UMg ztqcnZ$VfVZKR4nNtoZ?)o*4lKA?L-cm+38Vd~t*fGw8v zR+LE5m;IwYUEs4CbJT|~2FSz70|%*gyNL}JsSK5jdOdJE#I1!9$KUU`(gZQ3UVEp* z1*a?8w8XIVy~rDa$X}o)7kIdwcIDU498Bo;61vGLfB*{^d{4Ibf;aS9-rJk4;xfR^ z^J>3{=ml}hgB@dKeXo-F;2}-IT#cIOQ_-E@x_kM!LN#Gp8inN*>NpN9tz{(_bXIJC zkO=OoR%^8=oekO8@S18$bd!>RwEVLYD}rPQ==4V-7U7=gkBn{2iv&SrGU3FPL}kBq zT_kb`9}-Y*-xHT@ylqufuHUrR@d0(XrB$`F|d41U9!C(AY-_tM& z%ZweHy&DB+nB01UKWGu$4PO}d5f7HnSB5)pUXEqNj&Us&g8jk}D?0-2Uy#EE7cgex zmS^pDqo>-Av|U^a)&%Q7s2iOxSKN0JtU1dkt_>@o=`L4gwol&;lt^)tve^RqM~yl* z(NOV2>+W!yfynW4m;zy6R2Cnoq`t3QAJ=2m7?YM>-YaIksFZ)9()`+d-R|Uk7KOx| zMdYwHHA7a%etzmcd)-OIE|7Nd5lqB<#z@>L-~IwLP(9W;I$&a8VKx*y69klHxhf|c zPk|awe7>i3ayk(%=C78*@-Y4fi~D(7*bYa`4{cV6N8|YdhAc{AgCEf#GRvp=Dc^4t zRhC$>ZDzKV%>>5|2bs{jCdzI3J%0wm&qlH2H}dHiR-_%0zFhlmnUwn^3z*H8K0q23y^UQUH!;p_**gm(;=i#q>BNuHXW}EAHL^n&Z=BZAQa7-U_1^KC z|1lj4XHv2^dfe?}+kyjvWF7st;x1#Ex*p^Zs-3iUat>-K2NOnTmTd1K)n zL-*7nq|@nO5>)I^i8jd97b3=>X~-b^!nVMO7&`%vIWvhHRHs(fC&%wm_$v8PUq>If z$i*2cIZ*h%m??Tj65+)hFC`_u+fAa1%8`4T^aC6gjo_*hB(qlObwAIS3oLN{IiPa@02aIEgj+)3Re zQ_GTBFe&ep`&=0DKC35%8z#NTYOcA#{)Ek9unC6HWI_}0>;t7;1Ex};fYFU;Hs(5M zlvX^20#C|!3RN+2=*CvsXmm}+PMH`xU`mLXKsJKS*;QwQdnkYJs@sx-y8Q_(70b@W(k z_6<}V0rB`O=TT%?=|5(_yT@GDQUfc=bjj!tQeIFid!<7h}Hd-KzTbyjGqncu!=FMa}Y`6m0)Ml3Q%k_7Qa;R z54&ac{jjJy#0{6z>=LrnwQ@6yH{Z|JJ(~!xNfEc!$e~9>MGr@SGof7(_5_w_&)9MHEc$I|YLDn>(= zh|i!!u_@c&W4Z9|CzE>Dha1}u-ijIaPOtU2#lK?GquLtXc|axfZtf^ds{U42lKS7B zzr$%FjdZa_bl*s;X^9kN(iGXQ4kDNk$}UFuTKbz_^b`)mva8C9zNG7{{e#ph1LvaD zJn$I_N6@x2+Qaw;-?9XIj(F_?uk#P^nY^x{TaB|j$Fd3kvHZOIbxjM`hWy~!>I%?YJFP0wul{>6oQ%~1 zJoqGm@4&QoO_{hYWxa-zfjCG{-C}*64fN!i)`qRb8Ho-sbd^^H_*F`Nkp&YPkAW#6 zhw-cv9s8X++U9u&VScSu2ZcYC2CqW(WzP_gGI#o zDKcV5PYCqnehng}ADYjcb2?#;=K@LkBKd?F?S}~rWx?ZdGFC6FqaUXEi9Rhp$b7`1 z75kE^Ys4GrXrj>;W+lx^#GNG48UA6#DL+30dv87CZIre0BTMtV{e;~j7FdjpCcBwI zIVnq7C~=vhTs$8LQ!hixj5DS#BXo<)NT5q2$C2JCes|k1%dMQECxWGYIs$nJV@wev z>9Y)Shn=uwAS#Cjp42WK#m;_L{~ z$Nvx*csx-V#W%pEvhId&=DkL2?@=av^C}7$?5^bGg&zl5miy{ z!z4Bn9QAOy09S4M$DqKcmxQPYx+0U61Grj;(7-uEmc{!CQqXUgqR|@aEEm0BoK^+@ z=v>#)h@D&>^edp3j0Dhp-pYQHn0i>obTo-E4yJ$JFZnpMc3yv6_SEyfKk;0vUD|3A zHsD^z`Zz8A&s4bDnnLz!Q1mAM%=7nuz!6dC`LA8L1f35k_hrns=l3vmwMU#AOCrc0 zHD)B{?bH&LlfZ<-bEn5+&DP?}t0kqtTNZdt{^%#2#K|ar4zuuALEMsC?nGgf>=d|_ ziv6m_>)G3adM(e^gYs!L4eKKw+Z9M~2j!VEmHBwnGb^{&83s`L;9n%$A(*OpdclB1E2;A)urpFjosadfIswx;fK%JnGF=_M>cw&$}l1;8b`a$tOG-cJZOt zS!Nq25!o+;qAwb8W8Tse|Hf0?xXU`rhp^w8(8DvkrdMJf1+jNb8eY~;6mRyQ%MJR+ z%v=m)hwzJ18g~G6CG_-lk6)@B3bL?t9pMbhRlxd#ZTkyLm}YCTzFOMsc;Z&GfPs5RX(kMY`*!mZQXKQ)OV}Odhkp$iv{brNd&R0d;Pg@Rne)0aVMJ- zF^e&4^_&r4q>L0y2aVd}?KzlJD2GX5LzFAC=90Sg2HsSApKnQr9C`0LHOT~@24_dF z^6QK>>#Sw)46MT}f;Bfk_nhsbYqP@eQnA`6$>Ojk5`fZ8m~a%o4C3sk&n^d%>$bUF zvfKj%QYr3Yb=nStu<^$J%ciFxRt#e4Bd5zh<3602W~y6??md&I4Xs{~7c*#=a;t21 zoAIp9>MMK-c04K>(A*E&7~}^(d|&9r6M#~5Aej@Rne84EbkhjbzvF(Khtd^L=eTM| z_ARc38g6C(jw6qIRuX&In`{5u5)v=ST$)~w)}0lzr*E$;lCG|0VzQX!g0Ehx@uJq)|yVdr33++|}-K?^1i5vNZ+sTloz zBc1gQe6fM`5XH8bN_Fo>l0I4ZyQ)cT_o|5YgW}I&Fvy8Z&t)Ijp}r@yn9l_X3`F(`_35CZi-?=6 z!X5#+RKOs;N+@F~SjJbA391xL^z#r2<|y_UgmJR+ zOhIt4{94VDzHOr4{AN|x>cQllkvig-_J*2%cT%q|1u{n9a}_uiIugGKUX;C@jjT&~ z>7MfpXSrULpyiv1fkqd@bRWAKVH{U$wnSJF3!IxykLwffz%S5C66>gkqD{KJy z!w#^>H|#FyqiN&(5i5*XR8++>TRkaA$9ussnz&#dz^-Mavle0Xfw7l3EptS+Zw|lY zeB>%9X7kWq+d%BnSOJ|NyvU-n$$;ovac5RikypYRCtq+J^HZ2m7};0gZb!nt|N2ME zJ-j1bTo6a?z~i^(R8|10X(tPW6xY^EOAB+GuKCjT?o%2PQOX)zvQJbzb-{5sf-$ov4Yc{%!2# zYiTT_X(N`;FW%zcA@G0)Bw^>Gb~8XzMxY=2`s<05Q2hem-@iZ9NEKv%jw^;tB@raR zuuF1;)1xI?;yF`EaFopYx9N$lyE+-}MMWJdvCfbAu?jwyAhZ40`_#kQe5%<vCA{ zm+Hmi31LxAUhSVMa&n~Pot|qMa*oM@coy5Jj>~UgDwX99qVt}!e)1>uy*!2u4*u0- zA5^UQ2J+DsdKoK6r+M12_37p~Mf**P&l(3xD!bO0SQ5U%-SB^zHJB?ToB}ymv>{q* z_8la)O*`Fere;q6nokMQ7X!KG0(HDw^=JT2H*X!g&P+G^(8!vt_Ev==4hJYoG0`5D zIB%3pr7T5Q_^BNrG;u7XKWA=NbZ)2=!rT?sp&VW5H9N=ad(jer+Vt4I{@lxN0xcke z=d!^}=I^)=+r;Z-PG3v@vFau#Bz!+5$bmpAp%-a=MPkG^SDK0klSl+e6h3;$q# zaQYE=Hs_(aXT41SyYbp8VcZUu&3XIe>z z0)68I!^nA9PPkX}Bb4}CGU$!qC43X6Cm&sT^qk_J-NOirTZ;ks4@tSBOVRYLL%*dPVie=PuI7w!9)ZdS1^NQpX%mjI_Q)b zUuvEuWV-&P=zit+>?yFox~T<3i{=w{4LgtFNOyjm)b~)L_d*{I+vrrBggHFK5V_9q z^GXD2(kwS@rhRi5y^9{bEcWH!{eh0o$}2gDJAz%CUCdzDODrQGPi5ny%uzc?tOTCp zz&cSCb{BbndG*e-R&Iddn?6yHB9|uHx2^d+TfZ=r_=o;8>Rei|>$cbEH+ua}2U&I(b4OtknZ%G$1S zUkw^(u+o6v#+ZLW;B%o2?JPSyV4&Is3+}s_)T2TU(LDVHKhXEV>ao6)@{?a(I>vhRl}`Q4#T*&@2z4wO(4_n8=`UmD^)XxQ16W**~-W}IX&mOVsIuAl^s6by=+&O7>q?_^@5!2f2fH#!Zxevu zNuwMlgXps%o|Nm0rT1O*q6osVrkgWO;+>?b?YhqBs0;^l zPuO@$*o3scpR31;BpL(+wf^)X+z&~L<|DaR@BF&da{FVb3(q{o^Y+^1ID06HfjQ%l zUw!eR{d!IERZqhDpc0yWNa&vMLfT!XuoRX4D6=Z59UpDT#1 z>roN+Q%<)NRaFASbvo)eT9(UvgKBfPNffPnPM3IR*|p(mJ7`6L>^>{f3p1n3v_&>dbs)idy>pHE;}QyGUn$ zup+_p0L1)*4EiF0l%MT2zDZ@L5<`PIaH{|%PYx!H7KNC^ttit^+woBXz z7_lc*Z5GcxN&c0row#LQxQm#iI4E&VOTg3UIVP3J4yWjO-Qch!uE-}Lx4j%czo$BS zdbInnA%`Gcya)gLQO#X)9T+y^$e5l6CnYCm^IA^~vEtx9@bcFz(uz7yOL40F@#Evd z^|08OQP{KpefPlzG;3*=^ZhI7`@a7E;X=(K)xVBiqveD^3v+XSLL#CdgpAZ8u#Cvh z=s#~>A(&6(#YkU0`;(IWx8?M7nPm)puYGQAZo_;hwppRhGjxUhKQH}Ld@y@ES^$Sa zp=uXTjZ`?r#8fIODtO3nXhNX)u!sM7oEZO?{<537`7^)2stWVq?>-)GZf@Z9yPeek zK09rjE>mbo#{9q{f&kuh&h!2iBkMs{7xsVtvdie4?2Zo$GsVA19Wg@;G?4;ezWwj# zYbf*5-s0aL;zlw5KfTIGlQP1`uuMV(Isf;y2M;#d9t1piFthDb``_+a{8hIv+A(R0 z{^#=%v+4iO4}ZU8q>HqdI)$g*o#c&vdrl$y=@Z|gH}|}K+iQNB|L5V45k9T^oSkHn zEmuV?@(~_=rdjv*V)w^lCz-ggz~=kg{rfS>3%;gJCFkF7WrmU$Z`RU-_WwIAm^Rb? z|Gz2ya=UHm;1DHxTA(uQ)^e?nS=qeo2+<^EfmQsgY_TgE&*S7pMIqOn#Gd_Gw?)_{ zs$w9ELF}@-auI$#+=eTr=(ga&09(OJ&#;3ZC)fVJwfBN5f%1Ezo-G9lD^6`4F0dRXPcJHKd zvRivLW4&3wU6PHb%>V6!&D6*9#V_}tTI_DGPXBEyoLp$b2b=vpf$1PW`jsbUNV23K zY%&`5o0H9<(9NBS!Q2=XQN%=vzCz7{C(A8n95nOr>)lVEoQK4p5BD0JaS8s3l(aB5 z{#MekCwO%bAf^~0eDtCiT;acPy>LFlRx>AIc)JDqcMh=ujgigQ^ZO$T21oBa*SOQ= ztS3v5Li>#|>TPqHa*Ux4WUJLaE# zMs9cIY`WEN-eMBC&*$7B2H=;65npb8x9msBP-J4%%FN#doF0UKDAuV84h$4MMhp&J zFW$rJ4?9SM0yjYLRnW%e;1^MS*y;GmFI;%!*{q$I;Qh_9<>}TqkC2eUdiobpa`?rv z^CmK3q-xSYAuq)d>vjZi`|j;qHda``?xnT z4T;|Nw%lObE;J$x&g&{g##7ed*iDSxrkSj?fN=Ufh2d@4<{UcFSMfzkN&Y@h6G~ zVkZw$Z9<0&p31?QBcf-JU7swRSxQUl!<&u#**{mPCWoLeQ|$587yhCQn}E*2?VXhOof+v6dpO z;;g?i{omBsmB?dy?8Vmgrx~JhIUph=bd7AocbQCan7r8 zpm%SF0ry9M(GbHM6G3z+_r{0!RlZ^_OeOmT-7lwe76*pvQnyVBlX(#IQd1JGqx3-J2`bX+Yql-wqzb z-h8n#eBZJfuNxR>(VxUy3A=XvyW*$YlcN|>llu#C+xhyqvw1f|&x_@N%_U!4dg`oF z*sk@z0_f054!Uict+C7di@-`tykh-^cnZ%As()uElzSip@a3}Cxt##C6pY!hKStzc z*&aK1dwucAn69I-$FXQB)a=ce{(Z+=Ig0SJMO_J#n{r7oxwi z?>y(wIc#`;Y8b)ge0{KM_vK&pg&6dv7uj=&$QIhG^_@V0B~{=@F&NOZ7+zw%4v?(B zIqKc~i~Xi8&C)E=&$ZwFO7_eT_Y<8KLWx;zpEXR=g=`VDeHlzSqm6 z=1z@Sdza~ba-4t@KY;hQe?_y%@Yd>I2tiXEo?*Zcez#0{_YfqA8J1@y0j%Lm<2jh~ z{r^442LtwH=`EIm;vMz)g7@GeS*DT0?xd`|oi&0}}%XHWo6?Im_UVX@4eClAt zIMw^8+j%93VZ_?-TBm*^E5yRVp=@%$Zom0@gM8op`E4uU<`KEenA%AwRM_{ggxAcw zlIp`RSDjDCL6{NAh+U~AArP4{%7Q`Rf?JIB7|3m`gaC3W?+yY^+5zyWzw*&Z=JYDn zWdeM%jQb_A+Gbh;0NYg9#0)i4`+|=8YN}K8uPR78422H8l_3-VyCdp*AGSMB>bos7 zV?^`cHPznH$Mm>=V1PR5e@5L^Jy~B{D~l1MuKcN4f^T{HH!iw0pXay#2x7KP=ex`G zQH=VQ<6FS^Hr82r9|{_w#Mkcu=gZol4TTlN2A?X9D#+TN&PEW8Fb zq9~vOf*_!TNGl3TODk>AAWAnVVuC0LNOube2uOn%gmft_Azjk_&Fxk1y}$Q+$N2vE z7~VVdaL(RquXvvM%sJOO1rtc-L%+(k;x^TLd(jUblI(4%Vhb-lP6E6f@gCdBxQZ4 zTo~3BdXhkd>Cm?18H|0zJGOs+n#8|k+8WT}e(}{e+a)}}Wil6kdqyO}E+*oAdR64k z6ciL;GyiF|zuI&Tdc(}jOulNCzWE9HPqY@AhY4|T+wDXDzJYTzt^KlJn(a@NJ3{WN zIVP}e{lDKJxn@k@Z?qTMrZM%O+nn)uysQjZM?$+Yt-0z=4020`afF9`4{gM%)51VZ z9bW3MmzVi)b}h;79sj;6$(z}c%*w9uwc~Z=^L-&QAxk|B2~ML{PP0}6-pTgblZzcl z*;B~8fzqeHt+#DV3wB+%?LSu_dHvwbHwuyyU7tCsB12Z^LtxSckXKk;x*+&tr)|e# z`-Q$BE9(CPsop~mYq{Fg1+<@kKy4d4m*%ov&|3e@%b+N-1E*egOv;BW>`8o4QFQBc zeQ!irpv5_3OvZ7;2D*Hzn^X+T@ljZ+H{64dN z=BqAEbFR%~e?b$l7S;k)oU7IFm$Q9=X4}+FOX-PqRa3N)M)I?y=G;4qer-0p{SMs+ zIv%dD?yPzDZfzc5Rdkip%H-5|@pcc#l>r$ie~pzNzIA;*b!E1W zL2zQz&loBuW4mjlHOp&dxN5~{%1T#9M|5@Nk&OM_l_{Ck7lJDj9(8OhU2I5y#Fch) z)OiI@(Pb|TCJg*2XNyTl%6=TY*xI*?qmJHJP585$*Z%-&;g4)2oiV{fNjXnP3sxN` zbU#ts9UsZ;aFm}H!15BDFO|WiYc9}8Rbl2m)Dxp$daRs#w|(v-cdbQ}`UNW_hmvdA z-A#@oP5pqhPggoHiBNQG7ns^H@+HNEdh+F`YLtfk@3yef^&L#q$fIQVPgEcwA*Nxc z?p>?gZmPkmmC>=4r@`}|b)|b}TY-k(nDt2?Ig$+=G+^b}XT|t=d1UT8cYz$ z|I4LcbDI%h7Fjy8t3Vguwiw|gG+i%0;4o$vGCy|Trhp2uXv!xu*Yzi6ZBW*fLTX(V z`3dBS+GTO9AVdSGzK#H1HGu55J^wqa$2rQ0I`PD@&-@FsF57q?64@73UYoi6RN4a? zN9z|~CCL1WFot}{4z-iPv;4Nj2inj0YSXvV#Z_ z)g>4%(N)Jbi>8{ct|K;M`lxg(`6nfh99d|e&A&jQX@Bx0$4GPf6UWtAr;y;8H!(G( z3?T=5mknCYssw)K&w-c_X{TvrClSn{hd!GtzIAlu+Hm||Rz!-2!|@S7#`A9!<{Sp) zL&Qz2iw^)lElpO%0OC!YKR=aZm1n3hyo?kfQORSAd?T|slBqduWdxv9DY$5a8Pek^ z(XTIKNBJ`}OvMNVwJ(oaAti6o7+=fV^^o?K@P9|^3?qu?Gqm6ZrYM{yD9p!;HrBPa z9!%6M2qrM~ks}1QTCNjX-ksM)o*eoKV28++1bP)%{8|;g-ErK-yppHyrBjt^`;Wc0 zi!B|}3_<3*M$)PTr(9^3oRyL_q=*-m=R;O`@`lvM-j)8h1%*}oH-{P%-HJ&HNBc5b zZWfEFEh6tznU&xJ}JI4u7C zp1=S8e?)v>2ja2+_va9iy8id)=VbVw7yrM1dRRkeJ5SG!ga1jBKd)xJhr_O%C9{+9 zf36MK5P{QM|EG0JtHW(Jmm9QKRwtTx9ypNi+(EwM)|w6Emv*M7)_+zqlNd>esB7Xh zPSGxV<>&9n!KK2h&!aE({p|~BF4m|x{VV?W4?I48^P%(RyKi6rwYD#?gT}3o`R-<& z%`^6DzD*zIjb{5=XE!ox^f`9C%|?OD#LPUDy0~%czC&qWUnS=+h@+nON={BjnYz*2 z+dIyrBj5ZG$FKsPffF$;jwcYg?Nk z|933ROHcN)?4hI-*InCmR$o6ZH7(5|z1O&|uC8}%jE#YT0oUAdc>Awjsb}NRt*rm- z$B{hHsvB%0T7?A|RGE^Q>03~+sy!PZc{E+W?tAK@Ob~C>UKW+5@L8jD73~xI_Sv7Q zo#_5#(NnV1`^Ae`L@_REFHg_#z`%o75|v!<-Fw*iXQG4#>$m4-UAulgdA@aM1ou)D z7tl2N_RiHa5_P{Gf+OWAqnC68CC_P_bD;Tb-rUpK85$aT=)?Q>B{$f`;sfc8I4OI- zeG7Z>V$byOSNSz-)@&6#bc~Mfd|y?FvZZCl@x4!)GfhkuweB?-D4Lq4nwpv6VVxu% z+(hmuXk!D4-;e|q$QAe~?Kz+W0T^nL5)A8f= zRYI$;Qd8N9`+45rq_kL=()X*-nI3IZ4Gs?8%75$m`1mb6YHv?Z$+Z+lc6K?>7cXDN zE-l$}88<6@`}Xac`#(k9#rVLpmt|#Ty9N1jm_M;Tefl(`o7FxjFz~phrl!b+3lg6E z{QP^Us1hpzxS4r*RajYB+4pTFS|KpoO1p96M$$ExD!wJt;bwYc?RlvxiDgw)7@>l9 z@7_7?b~rQshbp_dsrbS6Wn>Ul_N}HOLuU@@c;K!A+>7NyAP}19Fh`)b)Ypa@#ot=ay22PuklAM})CE(?>#6OP}8X)hVal88? z6DzAvOiYY%4qAHq_Q^E+H4Q9N6{V%JUPq;jdh2%Y-tFz>MJr~|l+?!3v0aq z;KySYeSbSm(zoIVhTlK?O?L&OLHHvbcsfizM!NJ`N-Xkp+2_v+a&n%Vw`{Q(tUm_M z=L+~OMG=t=>o(QDbFFSd&pdzr9D{>DgVkX!cr@HGqP||?Bo2xB^%HuB=T@h4S9dpk zsnSfk;KPRxFJV$*Ax;;r+s=66#3cc{8R9N8!(VCb?Cj^mb9lXyx>ieiRIONP{@O`Fi4K|g-{;Jnp&hWF1@YgLez zmR2Tnpl=x5Cp);mFp=))QBf!Xul6n-rK4lSKTvDG_;4*O;&;E04DO^=C+WOK#cO^E zt5!OQSG&a$>xyU{7Ld^DQkqht3cVPw(@L)3>XMmMh@d)Z;w0ldH>cIb4q)IMy13Zb zi}KNuHDTu-(20HWplL!p8PNN42L!h{@6)`z@rX#xd3Kq`Eu(EY4JaWEEXJCWHQ5px z;z71agXVebxHNHrxHH0tpP!#+B<+Q#u_90QW^lQC9OMZ{LuzXNT=vM^hEUDSRx@GY zyR6$BuV1?sPvwhf_xA1S{aZ=1-o9l#azyypv16Ob$P#xgef;p@>)j4Fx2>-C@7Mm5 zjER7deo0O3)vH&>g9Pj{K3dpxcXb)?vvG1Nkdu>_m6dtc=qcFPWC;rk8|1EZeR!hH zspNP+GCW)u9rn!E*O!Tj3DYJVSDqeeQ5ISncR}DwO-;qP6jHVT1TwpjsxgR0$Ra{* z{_C%22?@+pzw;dN1o!tZ9Hpl}#>jXP%!W_tjri#-QkS!cOU-Gz9$1^<;o&zFK#= z=gzZpzb8j{J%=+XBQvwa*|TR2fN+9@HPsbHdFbgy;^N{SKYf}s@e<+l!>3Q>2I*x+ zrwl=n@q(<6EW1)Hv^?dtcI{d^u{(F}pq%2+4!(2X{SEdw{kmvm2010Az5jluY7%s% zlAxeqlYM?>W+uOYK=1eOM@>w|C_M)1Vm!*q%efpD%!!GllXgWa;FLEVa?_W0x^e7t z6`w!T&26}Of`*0$*YJ7zYp|VF1BHcTxHUvYKPKBQqqF3A_ZM<4^S@R}%$)t zAR3R3j{37}KStear=B#@)fH|t`F#L|QEbLo1$Re1ic$P$7W{h-ps`2h@DsmMy{u}n;o(Pu`Twjw5(8L`FFZXM zhehAGZ=un=)&0cH*3*QF!HYoa!=}lK$8g`zA&R-|8HubdCI>`x@ZiB0&z^-ImGak{ z>aQ7WNbqe$1c0mu+Ch?`(#{vW>h44LJ} zWIRQ;hmb}Ld*y7anMZD39+%aq+Lhxzh6YWD$&=qJa)wtrJGDeaMF;z9BK)zq=?1F9 z&iV7(q%O>kCEvTZ9?4Ryc7C#N8q$>n^8aIZckhsp5S^;v#E1(XOb7u%ycTk2&NySn zHl%7xpr$=1v@#b#7l%oU!FiIKn`@3x87%m(Ub$41?Be1Q>@agB-MB@mDRuAbgoFg0 z3V-bY8&wLW1jPs2sNz#u7#T}4GH#)f^kM@80~yQv_wVO*{%l+z}$A8qA9 z4C|kp==Qv^#SE~dXJmv$Y_K&ejTg_^ONltJ9u?c~pZdK&MWB0<^r-bV_KfC|MK^hAqf&z4V=TS;4* zax6z`p&!WiQX=Q^+r%~@bp6(XaM$+*X}6wVrWRym0`L3`V3;a@ujgLRDDWU zuZ9WE_v|L!|GQBSxg4FsB#P_1KY19gt}HhfI29Pr4EH`=<~k@~t01Rc+P6jc+_{9| zgoND;(ic6U0Kf3@iGK6u4O4IUorTI9?D_~(Oe`!>9KWwf0t1Z!>*v>bS|1*h6S*g{ zEVWXGf8xEi$1+!BObqj}V`4jZ?xf_t8OYAgUY}{ADORhj>0lw%#BV(w%Fe;j5G{4U zecwsp4I4JtqU^KidcP?TVjdoIb~JZV8qseEv#Rm^qum4lP<1#txIKW+DhU)p&ga+O_elpikjq*knvat3jlcfsDH9u8Ceov!m%FPGGsX^lRxLwJ8raC5Iqt$KF}D zk?G{gl;-ruPo5x=MP-@w4c5vb?^-pv?dP!m)1S^SCsbtu`K+W1Aov=#a%-3EQKww* z0A|iteUXEnKB_rA*l}TiDVc&rB@&r`g-_K_GBgB^jF=GuY#9P+D_?#KT>gY1SCtVgTC4`Jp77Y!l$IN zQW`k3_Qf&zDF|E2S;1It#QG*@R?=&IdpiSigGm!wK@fP8B%SwLUSD;AVtebub=%p| z#P&S9x+}js18C9NfX}dvxFmy2BM>pF{v=9|#i=@(zau};-;pCnIE|Y*iDf#}l&q|! z73$Azk_1*o-1Eoeq_>}6+*ub={ZCJ+GKPj*v*gj?$tmttf{T*dwryKz=~#(Ij!idg zk~Ybk_5r+jV?S@&avQU8p)O>Fj*X2iD<@|t>;ZKx!m5EU1L%RvTwbM3=sG0zXz zYCuILU@o%vUvk*uwCRr}BHkk^7@@Sgd=$eIg0cTpLNZ;_Q|dJhoncUDb>72vdQeeY zQ&#r5oVt3~`=~l%9F*PmalWyG?x}QUbQBY9h0QXIW z5J88Y(a}ohbJO%oc~gI=#rKp2B#w`Wtc?}C(BmZ&Z#0JT22qTB-@e#q&vvv3Mbt0? zDv5alW+7BYKuBapt#b0@NzX_$6XdZx{1$JA7xD=xNR;Y9LQd@&EJ8w>$T*MP+;YFq z_Vo5f2|6t3L6=ua(;?Fi4!i&6`=0_G5cQHW^0F<2jA>{T%3lSIzMMdN^ndh}5&<1y zb_xV~fBxdAytw$|5kQdBEE>6&!@|M{WD!}`IZN;#Iy%u^U0tj#GvnWiiGm10SrHLV zTuQ0|qfYP$Yu1s1$>6$CvV%o4U+t)u7_js8(BC)=;B0HB&kQ7My;4tl0$~`drs-6? z(JES-hcNMztcWvi$?)gUeTpS&etVqHX~iBOrZs~F#XB+~QMw^vv$ovCnkDiS5wO;6 z-1egMhMc6N8-Z}ZxbEU*nECAmSPh@8PgLdR;pH_bbY8aL@jT=kxO&t)>$aQPNYe8OcIxbm*R@6Y8Gym(Rn8mV<7HY!(EeoIj znswt_v~_gKfFWmQX4w5C|E_4Sfu>iB7#=pFI(_R5l6gG9nrQ!TP)~9`PM1VatKD{p zFt&(cIyV6`T?9$|>j%ZxnROh7jmLR^cO^+HyPNr+e~^&;ixt9?|3em#kU0PK57R($ z=HGCGAi;j$frRAz_?AuzC$j_Y>;V<#>&Fl1o(jmB%Y=;0qzQwkay)KqJh zK4Q6+*426a2KU6Z^qf&%ymc-hp#BI?|)I}>fLzg67v`t=FkKkYs9;%}Yr@Av%w z^7Q|7#WOlI@t=PVmVt+2W0RSmp9f-)1NBE&T3RZG8o{9TZ3>7A(02XDe|9D#fI)}- zq&rZ1@_;=!s5Yn7WpEx59Dk3M^UxtI+r`C;M#;+pSmzI}5k=`8@ zyoRLEr1eK{c{0zGcO)1btfj!Gzo`Bsm#Hc9k*{enAFF5O=;`T+S{%V-;4~6nA(>9P zO1jOY4w02(WI}up+lX~E+h$c>RP-%7Jq==KukqqfwSd~3nx~g^smPHjs;sY z;HMj0gIGV<%IX|2H2gKqGZN8Gy>6Z@e=Zz(OXR}eL$E|jC1`&cq)GPF*hgYvYH4+n z<@qAzg1k9LpxeZ%+m@C};Kv&x#dbINR&xsos9RJ}ZKL9)b14dSb|#?~Z+pk#7{FzC z^umP;qU&NApo2ur%~=afRi9hvrdf@JlqJa^6I>rI@m4%iBz-;?G0nH4KvN{Nfh z!5T1l&ZaN>e!eH*4y_oGt&P0+LsbnwCWAwZmh=nvVNs3G%~dn&t0b6?edL`-3CM_7 ziIBi$(yr#&)7>3G5MQ&SZCE$W*%k?=rlv%;g$z14nlsi2P)U?2U^75k3?jgKq2{TH zxR8$I3WAq_KHCN7LP1Tuv7Wewm^?rr^p_{EW1%G>6UM!MeFfK@J_UFrrctT0JZ(@ zq80^YTVE(wuAU+9CjQZj2+qWb6Fkz(?6&0CU zS^1*yM~%Xo`LT#OIrmylOnJIuizO^Iuapu{o!k7Da6;FBY_0(@W*jy~Wz~8ZW4>X_ zUd}Jovv;A9VBWR9$QYt*Tv%9W7Vg;MG}a_S9}#w6eK1QoS%au%!S>RD#Lg>Q0VmK8 z)ipJ*vZA7)%$qs6yz|rh_j+CLA9+UNl7#y#!vQS3?dtMu!a+?XrD()A2k2oyK3;T0 z#}Bq-Ca)}yIT^xR#V-&$i`oaWO%!lf<6CKCH8r(#V|+e6K6wmF;7R$pnCR$cop}|^ zU+X{+-r$rFuAv;17^F8^hagSa;_3Sd6Sy`EVy0byMacev7xb5KSLvg00 z;|+q6rcsvaYHB?_J?0 z7Gv#gdl#Z3BRTugU6GM=g!Ex)X~}ILcTt@^Y!WnTwpxD+1Q5gkDjw6wX31W#Hq=U7 zot@k$5hFz1v%5~BurO%JNF1>Ma&LHh`#NyVGDT(wkPB8OAzPtEig&^F(Fhzqd{$07 zwjskc1_6WNFO?Utor*P0ynA=8!^8&)TNI7GLqiGZZh~HHXf`)9^NNUw(13r* zU=e{wQBKbEtLAYEaMDajb{J1D{8)~)C!&1Pn8?$JYXc9UX5nzh|E^hR{)vDJ5HIrJ zW|=`36Wv^{!1LsdiL<{~dpJ2*~pY3W9A zf93<{tG0xhKrD6djbmHM5vm^-7ifw$H5Jfhz?NNHdDLN66Fj* z8WE)}QEzzCVYKo-4%yn-8DdKMa~b+Tv4~LCu!$1CMb>{bx#7T`J&}NXjl5I%3JnGZ z;Ashz?+y75i{>j!HbMM0au5ND)Bz4GK4>>JbrOohmc3CO8ODTT5?_S9i|6#|SS-}k z%g38jwVz<6p#!wp{V-h=l$4I5>f*ZDdf9Gf__@M<6*l#31#NBZ&0DwDKc~H*aQQOh zlMkj}Pt3MvnL!rtM9+$gi^D=uN!dghYn*fDoG!axJ%R}W<1uFDC)@t+&oeGSqePL7 z@G0iY+BXX<|3$~68S(?tiwh~49HJ-Ql8y`mWog!DlLOnR*MX6)QaOrvw+s}r;CZu8 z^F48Md*hlBnt;lvP#lC!D!KK-|j&<>p{h* z1fj1Ua79r?CEjisE7;|PPKZ!(w}HTI0G2l7&6Eid1T4bYeTL>xfU>f)kxRvq zT9PK_kVk?}-xkKC^8xJ*Du7e3`jCyabu3W~oVR#$q79*KoC2)J2@pKQHJS* zewXg^0ZPe4|3LJMvnz->EMeGdp{AS{nT!HFbdvYMLtXL4~iNO?%!|DCjx7-gpg!d z`T81%g{hRh{5O$Pu47-pK!=xQfc*ZF@A%D?Vz535SmCHl@Mo9xZJRlq3{|=h{OSuv zUW>uVH*YvWvKbE4MzK@66I2!<03(ni+78gH&OHdW{~?9}E;C3sK%pmo@#5QFodt2Z z^XK1_X?7^btIbRZk28y5D8Mermiw?6?|$tjdfnY{L1WO=i#6>2&ZSY%v;>>g5H7OC z{UA?jBgf7F<>nA2^}qJUlWojZGPP#7G5H3^u1H1Y37)stDp!{`&Q+Kd(hR!pqI9AC;axNTvW4 z0gd^vN)Q>Nwzih3g^hK|)2w@WNonCCPqoCma*8SI1$M*c`^QJ27 z-(Y}xL4Yw$`w7>(E-t-*)>v6XXn#G{E@55xMB~(YYD>D{ZBx_uy@8GQA?w|^5$Pt{ zEtO-152HfF63uDOZ(g783Bhg8-o2Lc9S{C;Oil)A+JtI~skkNkUOuAT=1rSwpks0A zRuZ-f^;|&{j5hhfgZ5H~6A?X-?nIE!q!W~rm9AXz16D%#w3zCb4L<(6&CZ%PAA0RIJQ8 z3c!-D9~Cb$Znw;diUN040=EHf*ubG3I1yC_KUzq|Z~a=@_~XZq;_+%vX1l7DJ>fh4 zS)TwHsH9vI3F^Sc+(#=bvjv9Zokf&*J3tv~5ujR{h6Q=JdP6NKxeOxVO6mVVp_%*L z(AvhP<`-#^ZK1OgfB);7-A5&3n`YZ0#k@#0zrRKG;i(Wa-lTOR7MsZoYQi^cA4@Lj z?CaCb+et=XQgHU?-50^*Mq_%E)YPPWbbv3LX8*BPQ!q-74MQev*@_?}%{iTUR|$;| z{t8S(FywGSe3N2(;uRS9sv$v{nT>7Czj7997ClP7ckjn_znBfRji|X{KnbY~5pw#_ z9T*e@2ScS~$12pvXk3@7I+uA>L*|}!g?$uHn-P{Ze7jQjgejS7~x6PMi_UzfykAh16@?|17S{C2!`0#{+ z5LO7vn(i2iujITL%5{I56dIs5xc^LXnn43D&NBenP6?7chy|02Ilh&{#trceQUS(W ze@}jbVIo6(Dksu10eAt{>mHLc#}CU$NDw!*9R3mp^#D?T4G|FFwk-fA@5hEACHxjl zb$no^(<;8=$5kH!T0`?e0OOU(kX1cg6nu%ifkFIUHjP&xm0O+;-~xM(Uk(*oov$LQ zjcm)2co47sK-L6YMQ9}UNy(S{vNc7Wogq}(l9G!p4n96U?A5;;Oz=gwBnTFM*Y4fZ zWz5MXS|?B`QrDu~#B`z;Gs&Ni*0BDzq2lGqb68sq031n3#|bc!5HJnz zhYYKoGt-=I*xT0^gTSI}I7=iwQ4i`w^z|Stq23Q3JV2~doZjdg6hu^rcy0|sjzE{h zV@fiCGbRKNG&{nNLw69O2RzJe^r+tu4y56b%7t2*fM3DQCgB8G!TkH@{RBt4_4Lhb z$as2Cc$N91t;X6>hH?k}CaZREIIgKLgVUJ?=7NNul_GeZ%NIPT8;D1sYKf7d0RmP> zd6GSn(Xwa9j!*)oXr0glsg4a4>42&hU|mtx?00W)T8}7CAV?G^1R8~}VPZuk-GJD> zBLgf$39lDj9Ka!#5m5w?ZaWwYOAG`H3C|Uf>r8N}5RZabZh;zX2+VU6^cZu@Ui(jhU*)3-u# z%k|68asObpq1oaV0XS_YZ)Sbw%2I-L0 zo}Ya%Xf`MDhk)Gy&aJ*dMrfH}+bRNiSlI|seT;B6JURvrd56#4?+3U?Bu!~dRE^n5 zE81E;+uhSc$H&L#PRS+ivT=J-Mge$>t-J~}#T^m_KX*W2<`Wk;hzJcm1JizxhU2`p z$ocaMEggAwR$vr!rHg*n`Y1?Xj+224pe7G!xxtL}^S*p)#5009T$;O0*g7)ckzrjjZnjQi(FNw$U5L~zjJ%bPvKz_#(HW@(N>z%*j95F>&*hyctKNxyQ&?^d1KGGc%w(>Zg4PY!2}c74k|>W+5jFKX5Uw7S2O0S*3x)(E zONro2=ytch2}7ShG5$MBgr4P?o1ecjK-&4Syrg7KF}c8ENa@3e4-Emcd~mxEA^;G9 z4_K}>BsW8|SN=Drg{@t;Zs6jttIfG0eE!F-GUOBR8j6%A3MGG((nM-UlyRy4<8SL! zhU2hPc^dK-7G=LHg~p`<$K^lNImu6!UCVK0UiTj%pi@~V@{f@4_n7~FoS*Oi=O3W( z|M^FOh$W#Py!D5k^ygxZhq<}A2_oA$;3y~O3+Z2Pch>BOmQGlYvK{`f0s$d(Q69l; z!r0gBEHqI=VufpH;ICg7*-^v>=hC4=XE4ZsvRA*eg?46>PIsYnVNt{&= zVqRr3Dl02vz7k$1d;-<9`R33Lr7SDl0WX&{G6spb^d;V7zjI*%KBBo z0!+t_$wCRkYVYN(;{6>7@VS%S%Fv<|HD>#3&VllI8*OHoKycgNKd0o4*2Q>;y6p=C z2Z87)iy3cd9a-MnpEBdB&_`y)XdAyIjOH3zT{ zC)OwQFM_&9<^Kj@I+*=W&yZwC-PKHJQ0bk9#UdSM>~iWc5K-90m+;XnxdE>DhA0UN zFgPlZfk6H?y}jMNXaD{<;9`Q;%(I=YCCG7f4hnLh=|N-_B-tRi^%H@h;t7_)+`Jxq zZ#a5V6LFydTH6aq`b0?uqMy)tQO_59-6!qEtR}J^6c_@>Lqm03UWh|HiytyteES^9z zeOM}({|XpoW#F&Tx82(ipnl4_Dc4+whlimG+{{UaVf>=!%xGHz8i{d{$j{G5bnQKM z&LvH+<_KXEAR-(cK?i}Zs+C~NBLx12Q$O`M6dvv{Z+B+)Ny^3vUQSUxU`Z`o8Fwv< zmxuBA>lEsoWS5&``_61^kf+xsSIL@xMxDj%R{2(J8x>z-p!|oy{a^1^{ym)WnH-KF zvXExWS9g{|VM^^=*@d9*sURyGhUb;=tgWjvUgThBrxSyC>KO?Om6#_Oaicz@oGMFu zd;44zI-Ib*fMeD}?tnlY60f#f?=R#|s7+BQ?OPtOpobb>UEzR+D;~e(jKp{VWLgir zlmxgzF$Xte+ArA!L?=YCI1s%wPD?4&*q~-$On>w!xK(4!&^p4}6D(k7fC)fs?S!6w zSd7Rxn0DCYBXjaJNwsqj3vY5*vZCXcvA8=Y4R%*wjzTvqPhNEo$ycglXpdS+Im|t0 z6)bYpYl3u{`}GZP#g9XCXFndG|5mt(Wm(X>bN1+ht%QH2Z@@2)xAUOlxat8Zf6nKb znX}2wq8BedOpHtn2ndMucj?{Ig7TGImkKL^STPE)*THp|K)^K+kNz+$Aye4YR%^YK zJW8PDqPrUiKn=?kQp?T7U_t{R*e{TzWk`y6&N_h2B(N25`0JxfZLuG=9*i<5Lw#aL z0EdpGyD>r3fOe<@7UeYiE{T8|i;zZWi7azcVq&tOX7=qP(d%s2%#aYF?^Ri>yp)x* z)Uk0fTxIdtn=7>5fyu9p`801fsy=aQ_ho#Sn{5J;KDXV5&yXWZ-4E&p`LBxL1P@u#Y?s&bKYW1E}C#@t`jXjS84O5d{B zi2T}>)k@N|9qZ}Q@QSI(gNvTCnjVm^;n~fVU zvI#X;Sblz7v5`x+_a;?2^NY-ww2xCB^|6lL1tuPS6a#3j_pR}JuNup4&pUavMNbWL z*e(Teu?Hj$PJLlm_^~SRs#?cA{*8W$3YWuxW#ZC6Xyx7@<=0NMc}qfV^&{6zD#VHZc53FlaVZE&R`L{U|KmSv+B?x#UD8RWtnP9$e~4frnK}( zo}g1&MwCu@+lRAO=3DD~E?n>ZKCG29<|i}VD5Ol!#F2SMHgSnl`$pi(QmGEUHc&KQ zgVldpl7?$CY01f5q~quif*!B><#;V887azE5i9e}Zw+XOeivLa$lOZm(rCo@YOI5* za{J#@&n4Q3o2GHZ;x|NSRb0U~fGnjx4FVm;13!a@lY>(5lv;pE4Cy6uZI2t{uH{?bsAGwWtYo|==5?be{5%G0_$c8e@G&wXV26`N&$bxqyEVB*>4rIm=s zTPJG1WHyx;Wt8Z>S{f@78SG-^419qkDX{ppqh~DNyw`@_P6m(25nagB*&Gt0Wk`Fb~CQF7A zi5)FnCh}9G@_EFSO)cLvO{Nv3rCVgbR`AQ(fOSi2(9kMjm>D%R7BW_?xjJiU9Kazi z!@nnrp+h~UXUa=C&v$d0h)jNthLy;MV~(SYQk1nrLcmxE@@;(afiDF4x zy>QOfRe#CNf*5XE9^L8MR(IQ#=d8^WHDjC>YHU)=oEmo9`@}q>9VyvNw(A<(j>#_1 zwf{A5mou0sqS_!3p0#q~xY9S4y!6HHlMTX}VhcYWEUV0Puc>gF7c>sw6W>0i7ZszM zsBGgZ;(3Fea;lWuZu;Hpqy@_b+J%lqzCoGEQ{@H?ik~Lm4_p&CHFAJ#fIK>+&#nG* z%%a}6>>Dg<0cr^;S#m8(2~$(ArVZ-eNd&YX2(voc8fWEWROeyG#Jt2m*>1aG-o{`^ zNYtP=z~zNm{AH&rucr%WHYetenPfy6mKtt1XyZGVe%|IiZ;eviyQ(v!Bhmn<4 zNlD2Eia+y{4|2v%YHES3+(X=~tkR(5h+AUo49>FHVq!?9e*jtG{JZ5&*K=!_^h)qJ`nZ zOV?cIxZ@SYdStjG4Mr!IdxjL}`Fi8Y}>6B4o z|0ze$NJn*-hQsyB369e8$R5hMzUmvL`^{zJsGUM14vt6-?i);KKY6w}H}i+fV`eAb z*hUu0p(5%;Ix&wKV+L+rJ3khs4Rf}7b#@+QF|yhrmSnTauM1*4>tvYN-(L`+*ESd) zrPKXXwklxlASvVLmcCfs>ms0%AR{SZlf@_IN!n2(YT~pv`Bm#$*QHF&(Z`$R@Nv3< znWt-PyETQ56@*@VR$wU$pZ zdk2WPGv%?pq~hz@lg0sqdAbWFna>kus4L|SMDqogyIoQ?vLsZc-MN&*-$9ONP7YFF~ z%50pjFMP?|uDe@C*YV-s7_ebTt_qt4eW4K(xCIfnaWD`9f%*_l0ZiyjVhHNBfLw&J z7q&(uPiUK5=KYtznH&Q_gxIcD&0~qJvrxGP!C?}3<|dyL zLONj$00(RVE{w2AFMtZQE(;AH|JUZ5j6_2RF5Rl&2H>H3*u+~lG7y3lYK3K|nNhy{ z=tZZ_xuN!eyl00u?K*jm?%@v4%O@iq%BJ^aiW-v3Dn{rf%B967vxy`&s~QQ*a){Dh zQ}}Dwl^dnGSp`Br%9pb}pG_s0=Z1JZ_;ju^tIxi2KG1AbYIJeZ(FsWQ1P2E#HY_bJ zU?&n_?whl%T{phRL`BKQD;yhHoxF=Q)6fO1d0ADp;1s@HsxW=W5v%;sFJCT?6dv8Q z@_1G(Od(W`sid@q>V4m-&I|Q}tJ@@brybZhDaqJs)A~8CYvwQWKbC4Fb(}2g6TW$f zTYw`|VX8Rhk=kER-et`?nP;$EU+!q~%}lSx0g)kPcM~bHsQjE&5)ac#Na>Ra-k3%27jiVWT4y=G)$)equKdxbye)h$PBE|_9dQ5jgY&SroX-81`vz8L)rQ6O z))j2O?s{AYAxq`qjmD z1HI5%(#ADgrxYV~zt0r8^wZr<5>37Fi9E<5?_fR4@M+f_!hapUNBnOtZKET?l{h%1 zCoia8dU+MY-n41^b~dF0Y#O%@j-T`H0lK4-lqw@L*z z6K@kuo1*vcKJGt8zS-aIh3?mWC0A;XJHg@%#n$7kE}U^Ag-cf}POw*Z&v|cjQ*})3 zuWFI-OR@Q+jegwJ8OGu8Xtav*%$+XxPo92>-y7DRX4_af`MrgunfNZv|pytwh+-iAsIZA=?1oz3#+Q*I?lGug?k5A<*Fukm9 z8A`uWw%I1(&+x5xN+~pHr{IRwun+RT>4tlAF0h~&NIa!@;OeI#=O4 zQBm|rnTL_cNX$oD{ZML$DJ2}cl1hgSTE}i_g3gAwV-nk^*kR+-psFU8Craw`wzj(bi&c0yGxrIO_cuj~Oyhl2rb!fT=={PohTHI>>c?=H$d%5J$pUmGgw$4xCU zAa|5srlM2C*5}mFY-ViV>T+v(N@v*!AMfJIM4^R$)3K`F7MY3L%rOF$FWyKV3HLHz zC@FjQaxb;?oAF!Wes(q=S%j`c7LIwh)NGwdPOPvb%c7ZW96fNMW!Er|8H1)%ueR|4 z%2?}Q|1kC0BLd9a5m|p76c3o>rw_Wp}N@I#b{!9*80ZX%2bAlV_&ZLhbvqxQU0~|?(JAgUt3@^Iq8FGfBDJ6ZQ>KjK~D~lS{})1=6Q+FO|Kep0?Q$RPx?C=B3c9{aj3!yOnD0 z?;omUzpi!th4==J#voeW!`@t)j+cff`)gWVtM<}FNiA=-&heq0tCSb?vwG;X@y*BL z`HF@sZd<3U_XM23CQiCH`u@dNm;X$d+^WJcI3}v~I6;YpU2Y*yS4i8@HP#I&wKd-% z0G8P^yyyNpymAy*_%i1$#5|*R{cDmI^{1l|$uZ&a=Z-BbX4OXNa~WUh*-2yj%s*IU zR^P6qREpn!4>@?q0sKZ?gEM(&w+{!DCixMep7}drHR45$TX9>|t2u zeE)NY{c|3C6LxFyquw=%102_B5m5mN867uOn23mMN$4n6Jd38y|z)#ho^7_2STNyZ;IvhPdMUcln{@N9Ej=Jw{&tO0PKgY6Xd&TKOIC#iSZ`EspYaD)O`5XL>PO`&Y*f@slP- z-S^_+*vR$$L0i%K<9wBmQyf?89ImUsdr2RmGCuNgQc~57)Q*|szNLALYTDqLo1v@q z(-)TnJH*8}&MnMm$u%}_O;=eb!pN4Vcit@e)yjqr*?`xnC%V#DE%eoxt%5sTY5gas zn>je=jc9F|=r!<-3vHJ=IxMKA4ERn&s|w^VOi*;~s$;ya{qen^hREiHwdUh-!iA~b z_TwK;NwW^hYHhmxcd{ljwrgTy;&*i}9JQ%DoSNu4!Mu{R(qEhK(>|NOoN(HD{E%{z zS{OlF@!WUaF*dV&CZZ;^M(gdNcz?r&pV;Bvj_`evqA&k_sh<<|&>hWx+WY%& z7d!t6d%v%;e%BoN@4x@LqVPi}I)Q<;zd!Z+x94wT=e*hEcd45l`BDlBdw>zng_?P9>cQPNOqXa$>rNf885IAdh+f4jd{_U}$&XzyU&W1V)bH_y_vjv)+QMRY0k> znHj#4Z-KqM=S4(r_m+{v7T^CRh1Q!%(Np@IxWJaf?I~A_@5?5taBZXJe`x}D&p~V; z?|$dHrB+t>p%pgO3Ka15Z`pC+Ksh$uMbSR#d^dSwVEsQ2F`eB&VUN zf+xBJYc{I;nVaU}_jaLjaW6S^x4|9$p`@gr&1wlJR34(Ey9dQ(Iih)Q*BIoBP0rB0 zSCU2;BwwBZ2X5YT!05@gYr=El_fKaqgbFJU?D*$??M~W!5)u-qJS1S%T;0=m3%t!! z8X=8W#(>N)*u^R^VOMdl=oxlL%#mlw$!t)AU#X-Ive_(go3t-o$Y8m*qo67HC5Pl+ znvY1y7B=rc!1#NJ{wfNIOjQ>aUW@%*J$Q<-<+r zXTE3s0B0!g=QU@9EKJAC>(9M`7d~N+oE$!EyxK~|`vM~Tn%CHyVbBmSg0g&O8g{`j zsOhaaRx&w8FhO9O5=FX-yGo+YMArvwVek6>T@=;)R~Xc!10eT=L+!^dKo8V2)!4Vo zs-C_63^tv8Nx8m}I3^mGy5~x+mcfae!`|LKFz_fK-~e{BH67bvH`Xoy<^3bJsP5x2 zrGu_f^y$+BJP}lT`A)$thKtbMr$*ZXU~1?d9hHXY2-)SnWe%_~E>sE=r#`$hFsQ%L ztGNq@Wl06&J!^)u9aY6X5oe3fJjie}A6)X~dw`K+H|;60U!^c1&Y!>`C>?`>Fz&sB z*b`;;XG(5PGE!DENcV@6Ayg@$qa_8$qNRfHxMtG#?ORdkSr;7bNlxj0AFVHFnmj|y z%oY851DrT8brn7JIf%~})&TOkY%u24*dGisu^84X*@Omr7!9`WJK>Cree3PTzHw6Q zVZ*s7Tb!Rzuw64Tsp>8FP4~*u%(Z@wIxGUyQP6=G+ZXYzdHKZt7VM&Z3U5hha*Kv^B|qQ)KR<#9j7t>g|9t`M7F^8=eX}{CoJNUcY`_V%3Tr4ok2Z3rESN zm=DOkN=*EkW5pKYw88`9GDb8!IeB{z=?-Ee{L=g+kJacw2z=4dr64-@wwRnXzHt8h z33xBCrRXaTuR;f4b8IynHn6EXCnmDMe-B8SYT7GK9A+f$&GZ5F#eN}2ez-tS^YN8S zm3BBuyCEXx&2WKZC7furSMCZO=?|D(J=?*?G&6Uu1*;_jYy8FWE1t-&;g=ZO%N(%* zSxQIeyQ)AV_7*`JIoFgVH>2_=7msNo4nPs;g0;q)Z3HI*;6Ng|SH?KJL<-?pmT^zB zmI>a1vw5&_utY@U=UQ_XjW{bK;{gX>8jL_8ElP{u5dx*v}tsKmWsg ztUUpBJUTRKy~78ZZ(75yR+Lk&t)_w)Gi)}vHQJh$nV|_nnn^inNy%dxA2-5*$U?FQ1k7rJ2#NzS>k*S6o{92=187Be_r%PzYaz28eGjDhjW}if4<-T=h>2 zg0IvfpY~4cTjw)t3y|1NmgXkzJ$R6Y&|yD>h4j{bo*nI~pP$9T0+q3*t#AzfL2N={ z#mjW3PWi;fG8zx)Vu!>CMJJ)OR<01IejVbz{sqeeVZC!~tP18mVnon#=0>%<5Tjq> zWL<^9d@_~GmwOg>wO3a^yUQN_q)rL*;|B{{EDKJV3JP&|cSqRu3V7ypb6ojue)wBX zy?whg+^$b3Z+56inPYa_ta?|)Yf{=JANdd)!0*8WU5(u}*!v-j!x)MRBALA3zkffz zG;c<1Ne6bBpDkFeK;R}~Dj-21&ZL1CFF&IKn+@-8qbh@|_%nLw3djMR20-jIBO%hr z9!D~a=zffqjbPNw=LbKjjk}z`aDfA1Vy%ZN;v~+bkuPv` zK$ABXVtQxU&9XvT|AuWBIFjz9^|%(&9})r_8eQ0B4&%j_RP8MwUYnFs9zJ?>6=wLY z``Pcow^j}Ngy8a&JUCa<9_c%`hQFNrf7p8usHnECOSH@Zb3#QyuP6o(6#US zMUcB)tj4i|JV2S9o>Du*KhO~?fCw2 z{gFC#&e?mfFxOmj0hCQc^cQbGv=jB=NhXuhAaOJaYWI=|E6xE}CDzYrF3-f@oiu4v zaJ~q`2vnvS92|wMe@3&$nrKz%Nqk_rp-p_ABRE?^xUB%~bsF-|e-(vs$%nY&Axv=$ zY$N0j9B|>dlhcm4Xzs@2ul68tRDFMGH4a3Q@6a#!cy@Cruu&)!gpriEFi7;Q|Ak;Y~J=V^2g#yN{ty*dG=Fk6t z&}ON)1wS$Uh=PnI_#n}VU5w;$r>fkYJ9oVO{HWhqLZYIATi!nM_P!0eNM0lg83E0W zAocPK2-K~s4dNUW_{o-C^o8ZES;A%NIq4lW@^hWgsgpK8-$*aF^!f4R-eG-{zHj+K zTNhVW491}8>IwYl$y2A!>FVBj_G}HDXb5)XloTlxZxZu9eVT-D0qP=-DJfEL+{ePz zRJm;VbHG8obonxgC@A=m4^}BsD}4@Px;^spGeKEh%EdKl%lRz#iJ{YR{|1bd0Ic=V z=ZBV2K+ySsm_^KiB>^tMgvW@PkG(iN!4W$fk}wRg_fxU0r*m*@w4T1m;DOrJdlRD!3(BVr# z7qAl+5l4EiOoT=f|hk$C&pEpnD<$l zCOg#I#nuYgSOx3u;+D9Q3gg^4duA3#<(60l z$BpRqr$JEf0AiG1D;&@XWIlE4jIpTZT3nz3>Fek%FskgGg6wE7HYeP9K5`p8tJA(` zPr&6eo;5JBqhbQdpOf}4S+ay!D#DoNM<1U!lE*XfT(g#MpT1_z8U)FyXap{Xv>9Sc z8Kd|H_@ToukFJ&Xp&0-J@)eGw>PS82t$QHgvoN> z@CmWT?Yno+!J?9Y2b{8r7o}x7vgA*mJc-Z;|5*z9wEM>6@(u5~g!T5o>Ui%o-v}2T z0;^ThOlCqzp{EGYH5I`EI|XB-MWd-L#;CJA=rR=M*I$QVmM`+~?1q zW9zs>}K{s;thaI67cH~)gWbIV) z-f|Tz9|}O!-AHqAP)lhX8kyDtS=%bNEPx6?J->QFbZR$Z9RD4cuaO86=Ai=ws{%;L zAO|^kWZFQI?V+11gJhqimY4e@L0ZyZJbTuxjt4I);!Sl@;u|KkGN?4Dhx#B%0)cD2 zhddyFu!ZhotI1EhE>P(7|py zJBPxynl%?cLT@YK|8}lT@$%vXih+z-CGiciHVLba8_260Ctsi<3bF3``N3bz^kPMV zFv-1;f7?OgiqO5x)@7 z(j7Oqg$Un+u~Tq0l8Pi69&b%YlB}&8+22(^@z#x;H3!{t-=d0R^_BAs0$nsj-a#L! zJ{#ScoQS(y)FK^jAo0QFS84?GiW-~g+1g6nx^;`B-$>g#p%Jk7-uYIYG4le3ofI$p&xa5bzG9kk%lN#p+0{5=8iq7d^olZ=N3PBN9Qj zD*Sbj1p&&adSEENb7#H2C>k@l4gg@-t`sPdAAaw_gIrOk5yJ^DEE3^w; zYAO;4IFFag%g_HN)nXqg+X8Gg7sNk>U<1k0MUBe6k)L(Pq-*QzXQSQvN(E;{1h-Hs zenT^najn$C(ozS~zQ)Zqh^oI-@PnF!vF zZ1l+S7jygh^QWl&t&W0=l}Kx^g8fllRh5do<|Kk5K1KgjSYrgEt(D355J`ZDv{qR7 zI9F9qZ*K!^6nRXDSUp51S^H2gL%(6rE&yUqTlBuIN6*pko}P6(c6g(C!5xmS=Esj+ zF#N@kti*vuommJ9IxYU0W5@Ew6&t`3x)llCHu?;3sNta9pspJ=Sm&A-v8ipa!)np7 z{6njjQHMWpjXu?3+RkV@!McD>V%ZRAEjgJ-1e#z901@^%MH`+!Pudp<97|GZxJvYu zk$4rm0a-~6D7J{33!zS7RGIWLY)d|2>c^Viqb7yhnIfK!{a+wnPEZj3`E~&Ve;Q6CJKRr3W>bi zPEOM(h)6#I9>X{MXd6cGaM`uu;-|S~#(Y=xVk_m0ybeY&jIdXAOp$CRD4zQj_Ev8ZXD?CrSK{QURPcN!3H zvf*QD4^p72>gtZr9ZpYkeq`&vvSJl#al(6I9@`2#J3B1J%$pNY7?6XH}Gym6R;j-K_lQ6;^+SvP;o@5UL@dvFpe-&uMd3+=jxHSvk)k zf)C+4LL10EZ#chZ9B*BHg94s1!N*{mfNAh;+;|r^h|utDbab#mNhG{Askgh!XYSpL z%=OPVGW@sO(raLb2*8SgR>49pM`{1Y*r9(Ll4!4AcB_7-MlpY!wQXoZmuFwbQ&nrdx$c<`)Lq-aTy8#`tis-)}p9N>;1=KS00aLoX4A>~VCrgP5E64uS zTK7>~Tl+UUIr9P7K!S@EOUHPv`=EVg&gLI|ifW~%I&e`Cy@Qo+R0SPxP2O{7!TW@Sb9#CkSN>6%c>DHrbgUnO z4PUoz9RjWy@C)b)$c24ZjWt+C0Zg$K+o}O(<8yjCyo}9>Hz#)?YQI{B-uP`0aeQ^` zi8korEs%cjiYk@AP@y#zHrkdy$$X~QPsjiaMs#`Nh` zNYKc;{o%y34Z>{{*!2wH$}mD7)6#C?B^*I}F&e85genFQz{)X?7Ez{onb{0e{Rf^3 zF)h~dIv_?8?BX>6@7iM9cWI~DPZ=x?0a;-sNpw$y8j&A5$~qH*?#|v=e1-z$AW|Md zCj$iaQV~~iv^b&cuyDZwS!nd)q%2*&yaVyhSsk7IXl9r`Yu4wyyzsA`_9dVUyfJ54IUBr3pjktg)c8#dg5X4_pX=h<`TKH`_!;d9YN zi12a22pEbO5nH-BhCY*Mni6-jV68klr9&lS0m*E!=`lcTpHHVZ0ALA4r(S=cGd}VT zF+X}wFcd%s$^yk@Wu1NPTF^>6aNt1dr%xnrga+y%y!Q8YOc9ie5aUnSy?ZwrO&_33 z-_~W!{8cG&_CbS#AMM+eGyNTPYVR-Y(iy^epK!7G?P?g33vhC_014R2nWcEcNJzLg z9(&>V%7_g^u`|(v*+Q7}*jkKEV zHsZUB-=19|ZgC&sS|nm>Ji%@dXt10FnTJQZM0DOu%79pMzE2Je2CeC~P;7+* zbVAK)9^z#{V#QPkX~aAsfK&V>tX%QJ-lAdvY@4`s_$ai=!bk(a%?p2CjO%PCSPWcm z(W0e2ot-GneuWMXI&re`*;%!7WW{WH_;Ja7_y=UgXj^xVixUMhhCWk=ki#MXH=rsW_j?$ zXsu;^LMhK%!fG1?%+H`)cyar39NPou&iz4%PXq%85O$NB1_|J2rpDAkn=+85$jc+u z$&DLdeYHQl(F0+-FRU%_tIRj5Q6~X^qTM`~tF6N8IuqFy$?L#lL=>C`B;P9LMz3Gs zGECDU#s$6U&m}{lld-rj3EIy==n2EoiU({A8nGJHo)iyI@{vU~*t}HQesBjU$AChY zB9y?|&zL>?3)BL>>c>HlM&4_4F36hi0Zt;@szuD46C}-pkQ&k$1QR2h0Lb-rqw@D( z^}BIEPK2vv0#XHzaSqzBrCNT#-*H~Q;KU&MBn52Ss|=VE2)KR3-n?|_QWbg6I2Wkl zJwRUk0~Jm5knKSIZTGENAD|SDCPW;nTr8O`3>;9r5M-QaNv{piF&T@BWa|6uRsv>_ zVm1o_i^Ul#oH20X#o?P_YeWIhM1(dK|vBh-VJQwk(b8~1xW=U zc@;v-A8BHBmp}g~PG$Wftb4#A3FLqsXlQrFTgC8My3Fyg*!-zt@!B4#=W9=dJpIy z&MA{NcN=wff7!Yp_+xG-v1`feQa%RFcsfs2h9bC+)$3sJbQj?%c zI0wKF+!eWVXXm*t;sN_AAAf@v&IgbIGl3*B80j74sJmj)m5&+!azfjoUQ{NEby;|O z_w3rzK7V%c@Hqandq|R&(-cUDZ`610gxxc1DTNmazv$2d6}b|xm>6N$w;C84P)N|! zsCgL1m#&eB^3KKVi*(>bsLq@Nn-e}7_IpZdP7Z0lGJyyXUE?(Xl%sJ*>d3ERCUJHU zOb2ERiO2!0f!Vdzr0w(i5POvNUL#-6Y(r(Dl#&1>1L?(gDN~#{Vj4?(-=YMl&y*WC z?ljl-GNcl?Y(Hdg0QTpr_F`(=v;2!N0Ff4|+Snw~p8-@6dw^N1K_KSHx0W%EP01Ch?|#(t!h22m(qO(wzf8aJC4H7;-cd5jp(t z8N5!M59-%C!KQC77lO*cM`Q!8PpuOVg+@5szC2ir(b*bFS9V>zh*pcu{o%O3uRgu+ zAM1Nqs&^u4!T!#{Iax0sBfwO8a6GE-Z1NNqfdhp(#|1O zd>7WMyHwu;AV48aknMm_4l|YK!VFJ?4Tf~0Ba*hf_J-P8;=h3Rajp`b^!|{~Hj0D; zOHIeYDjSj7`Xf(o+K^1pu6~o{BU(~ z=p03Nei}xl2P=S=UNa@|B($_ain(^?CRCs&lXC@= z6cE1$>QV(aVRI?*S04kR(VaH5tJU^7!XQ8-0atDCmwx+RJCCR+Arx08nM_+>pDUMy zk`F11A(p^aotB!F^(xhZO_Vbr7Az$l~+`sqf zO%;sLX4*q9erMfv*rZQ*HnSe(6?kWA31)IkQ$%6tT1WY^&d<63yS-pWTT9f_x9{Ga zMbuBy`Y>tHh^A>WeDea`-QA7f?mF8LAR4-*cIuAKzVDu- zw8QBF47}mxrE)a_l0L%VAgn`747UPA7Eb-e~25$=KES$xI65Go2O?_Y0JGD#OyGH zi(#zsj{9(+J6k>#7cbS<*N6GvDk72wgPOu4 z@mYpnyt!F$W6UY^quZEm6Q2NG(GLho%(vOxBg7%Nj!uvQD5T&8aqq3d!e5GtJh505 zLc$5SpZjqzP-@dFbb7ZV*MXCQ!tDicipoLzdC-d2M4QX$r`EVO-0(C<6z9MUvmjbC#+t;>p^Sv62V}c1c@f3zzudam$-TD zccrRrQzYM9-F5-JgSKdd;y)EV9jp$=36lU!|A0142##gx0vd6EYVTbHse`WY4^>S~ z*?5~XD^hllOdDe$KVT7Gs79>=UZL~x#*9+Rv0Vm+hW!}xuuQ~YDJ&O3Zb3f-Ui%XT zendPWINFF2j`1Z%t_NBo3lSr@re~xa&n5a03G!CZ*I*2fU4(-T0yhe9`YK7um53n> zEiND#^BF0X?R|Ny0I{B$x;lrt;?|9w-oCy^iHKPpUe~9zw0&I1>Mdt20yi%q_M3&z zw)2E$MS%}Ej{`J_`y-`u7?0$wCx;UBPo4}~{2gF#ANs*a(Fbo7TcEnRd9c(F`^3Dp z1%SIA9d+S*s819C3IJPUX3I1R_(MqYvEr8N(T)Sed3}KuHB2XsPLC_5iPz?tCX%gU zs)DE)Nzbt=Q;hErCp;Hi@7B?mpL25`AS{8$IQlaNrNBja8&6>aKsShjq&;lLGPoN; z^F*)$Z-Bbgkuz`m&*Mg(A;&<`X9iqsf@PcHfdkWlLy^20cqw{SaMCXzrtD|68WcXC z4IT)&0>sI-UdUOBfF}**5E6AE4~3VThJh1MK}9_cCJc258q(jBk=iqGMT9>xp$2hd zfaj5=AXT@B`=}M+&WZJgM@QQ3CiwgG6WJ-N;udj6Ot!~^e8x`lmUfVW+umzbSW@DH zt$YnI76s(fmY9V*qHtJ}sZDrIFe>cn~1ZflxLV+uh&aA1>kZhYu5Ak72J5 z0vAN37krT=?}L)0>pSJIq9lJA#9Rva61z}ShvkLWJc5QJ$R`3C%<46TNkXdl2TE7~ z*{rsWAiY&V;s^E*niJ9F&uMAf5F3MC@ZP*>38>*N4~G*;Ecge_a}OD)sz37el?OsL z^ZqH$C7CDIFCs8ABywAl_Ak<^d)HlMuq|gAn)eQa~xs1$@&qh5xfrtb6U1eojSFY{|6GHqY)aCNHg{#Fh^Mb zkw$Zd2U&>jVF9-y2zruPL;*of--DpetwpLX;Cz+Gk7D)hoWhufhj0Rfi8_#PNr47& z*+H!L=<^HC@55xmAK3cX2TOK1D4$(Zl$@MQ`t9H{sQSm4AflkIvJOSu51&6zMo9t9 zm^;9dCl4tg5cbs&9eAo#dr9y@&6Vy zSWZEWjKvExR-p88m9VSEPBvZ*ekiC6s+5AA3ZJWwj~rr4R08_?`hLUr0QRL2CMPXO znw}Di=!*dGND`s3r`EiUCOcU2fLn4vY3MoXq$ddTYv#;q6wJtO-Raz2M)XoaNW@;O zMpe30Eam3BBrnP(Ma4PzLR8%3oW>T1+|XzCdST(k04h;;k`L(!n`+O{O*0Mzoo6ff zv0&9AfNFr@1WpW|we$7slkhUrK?#MdEb9AtSiRcK^A4o7B@(y;$VPC0=1vg(P-5sr zPJRYy70==`N7pY34h}v83Rx=9E4-s?<@~Z^h0D>sbX9vW#j}#R;|a1+6E@3^(5%oZ z2&P_? zz#Mh3RFK5xEKO|z#)KdaT_etb3FfU>fwBu>%SIcPEkPVdsGz7c0!KIpstO?@+~<}g z#T~@M9{~YuK+ueHL*Nn@PtP=L>SdUF6)P~h*+&=nw!^mM-tU)ymOum1;Us1lL(~{9 zWtHg9F8F)6jJjXb+qsdE5Sl*#%o_koz)bmw0^p`in<$8!OTddEa2KLA1bb1S7Lf!V zXmvbH2eL&95Z?mWG#KM}iF(3Y4h%hvKok0a)_slu`XNuNV7 z1b8D`2;|lIh|z8JU?MP_ae;MnPfe8Ysw!$!02m-1$yiv3pwXbT z$^f zU;Q1ZS>nY}fI^|TTn|w2Xuaz6yCRx#0RbzKp7CL%>CQdG&b+g1J95IqX~>CcI!XJ2 zNJ^3Op+mCw4MxI&|rf}%oeXphZdu6|ze7fg>?wb>S1+VgN zUOXrqyZ(sE?VXNy?;lC3JQJ%8w5lhRgni4G zFE2p6ZQFiN(;#ICJuV&4xvYO*^H9H1pL8_}aVNHOfp(yC{1)ZIDA zx#qk-?;K>)8jqPB+JMV7WZv>Pa5sCmpxo;XLJ@im#E=OIxeR}trvR9!vZ|^Nwmqg&(@K#|9PM9uq2@_k(lfpB$%CW$yK0 z#-pU>K!Mk+k?)bYF(x1S2P6xJ|KJ0~b1_FLObtUv#4wu-AWD`0rH?b>f863Kz$2HI zmL5BPJR~6@!HNycFZ9)`jrdKK&e)Yq;F1}RBiFH=9&(G)w<Z~=j`SX)wO2cJU+9|*fTtS%+?c6^;hE8^qr z+qc(35i$>7%^eh_e4!y z)WN!}GBQhTm8bR8o*25OgXHj#oPbzMkjmvyvhrMEnzI$OdS%3Xo~TIG!#OI!)uE2; za!f@f6s$jXuLIjl>!DbhqpZclBspI%yCow7i`ZRnBgnc22WyAw z_pQr>Vc-TE7!oymSnM-(Lio3NsaIbnB}oAP%0pVBtfJ!e{Q0`;6Z@|S^j3mm3^LyiDBg{j zC)}e;5tqa3SFgs*2!HpeuJ!n%QU0qz8F`|=d9-meC9`16PW{tw{a0f)`j-Cs;{NFt z{(Rx%Z}-nz_^U1a>%}SKpPM&kYXAD6|G{q=zq^0^=#>A(7i=3ma<)g`_o;UyM{(r; zB`$3AZ)2DL_YcoJ((b-iNhixS^udUiq6~Yy;qUpI-SJQFe|!PQ-{U{+jw(mxQrEdg zmv)~|i4Rec>OIlGo9SjKQk&M1kaReKnM6Lezh-mE>82e(D|Z zaXTB{DDf{ElXfon=w;2S_tX&I%UD^u_-<#eK(d7C=u6c7@xwB`BhQ98e1^$@K`Ku& zSOP#d){%K~5PXu@H1@mae}Fh~6>VUq#ImD)wpK3CAnJ!?uLHHs&Yc?-&u?^kD6(WZ zSHOm~nC^AR(9n>?Ok|2M&N|oY8%hUC2#*u6o(%GM@!Zyq49aWp=gDfGME!V zT-i+>`;HWDjXoEaC5fn@B5|gZ zLDU0vU}w>2ZF8Gj+`>Q+gC&zdyYLY)Jmu@_yA55(gI%H06?`@3D9|=|sAy!qOXv3E zWe&1NEWBgU%dX!3DmI*z3n=-`(P2Pq`+v-J@bX_UC$7MesBk zv+9jIqJoA9VT6^MZUdpt3vdy+4nbhBDl*XFVB=Z~R#qP7nz`}DBi`&Sxe{PjAh%)T zMm?5|vT~tRvct$*fh2J21AMA^fgPiji_y2Q)WJfA^{S9#*_Gclg;$ zJ(-ab-&Jt1(?06DL*FMJ(r&IAZ*rd7VXz$-!)Cbxq$OlkfF6ncdhyKH%hH~Cl*Slp zwH$U-awd%-UiA)e>ulitK@fN$gn7AGnj^I3?ty(g$d8UUh;+X3nI zVD~w*GZ1n_0&6b6oW8QZmQT8|Vl?cVZ*OUW$?k0yK~z=~wUW>IxU#YvX4?FL&_;0% zn%yib8u+C9<;XsP(i6S^!(4lp>vMLl7cIZEdw98715LR{dPS-I3Mt)T#^=$qC|+TY zvPC?`>-kYxt(MfpY%L(R8!%!{2~C5(entr!r~}_4Oe(D!>U{OXre8zPsrtJQhC92TEbK zKwLSX0aqv-Ya>!57a?Kj;LrWiSq;+ce)8;<0wb#q1JRNQ#KfB)_ytbZbf)g945wwA*X-JuSfA_sAVuh(V! zM2v?%4-8kVCAzQ!^Y*lXb8HZ(u)0DWtP>1HDLuaNx!*RZB)NNd2s;&{2+I#$CB{He zTt{Dx^YGa~)lBH@#~ZfwLP42imxP9gZ$=p)12zD7PLg`7gHqnJm%2=Iw;=0ZFOkEq zmD>hr9MugW1k?x6XnqvZ;lP&3z9PY;eSfxQJv!XFj7E>!bgFn`X-tz*uUM_i?w(97 zs8kb{H+e8c@s?=Yo~R&&Cxpj~nZCcW)v zB3sH9O=*7s!srIX2qYMCb@%epF+MjC=$~#%lcW!JBhM}XbO=V_)`On>nP|^6ZGM+d z>>aFAmX@=mXPHrAZsMqp__>!2wk~H91u@257=c&(uUD^0=&jD((6aT4(@G)j-kU2| z_a^5xfl5KcYI>m{h~A{FKG0Q|wmd>o%o%xEeFU^T{EXR{558G*u$t4f{RH1H-0cr%fKx*E(4V|NI$UC~Myf?ktGbcu)s-MOlq>;TYhMWS)k#jIa|HYc$eoE3BwMCxRtmH)GTPAs84Z#SUbIStl zdP*dEinYXk+*sJ*jH7IY(<*ei`ZI4PYMep5RxL4fS6&jnP2p5?0cE(gTZ`tsbq%N5 zrCljFWTd|t5WW)lRDK}pNkfk#hqOK3QL_C5pc@cYJ2L5xSFFxmxdYPbqCB6#(p1Ke zNc@>xwj=EwkXAD3o4MN)fPE35~*GSsIsd42j&a|6&>-#l~{ya-Sm>n&~4&s<2l|?Rw5ZoUL21$I# zlj4ST@ax31qPkUSs%BxyO(4-ETV@#}k58)o&S2Fv>5RoHYLAfC`r{po3pkI8&_}P> z%kI)sUoFS#`Tb1Fbs9-yO)&T+Bq>bBbLiZgBoEWHi*hPh_K6Gr zhpZ7Pr#5Qh$hJbS4!@QRC+c>zdYmWodXe`4PgdW|^eu|~);WXE--TqV5k{s3a(pw! zasu7eKPrj{f>z1H$nq z`7?YU|FZx8Gmp140p@uWM&K!y(iMAGr(IXzw8y>4+kluqMpd16PGi+v${`_z zp1!^*!nigIh66LsA$zsc3bLE$cAX@ifEbnJHalZ4dS~T|bft$#Mf}%R? zavI1nCOKQvYXKN3?%w@rf+P#nMG`K%1|z0DzK7xb%NracKZKycFm8zzy%?xu3kwoe zHiY`MJ1l4eYUi}DxJtsds(&C_nE^&wM;e!LE&eYDG-%dU=bBF!!8pPNU3p_-Vn|?k z&p{wMP3z$(C|64fXgR%p5iy|+7@U+R#}|Nt^K)%LacwKQRYfcpp=qXAj95=R~dDt=CNvm<%n+X6}=^%m9W zi%0ActT)I!Oo2l<7%BM}b4M$-QWb!k^jw*0jQ?09(g>18oP;KZPMN}0o`--OiN6YA zf$sB2OMw=igUKr1u(oq;SMZ!5>$dwB_TZ_#2MiyiuNcb;r}?7j@El;yhRvJvW{Z}) zpq*G7lpEv;yThrh0reiijT^HN%#zSkG(8qmkpx2nt@X(2@-9OjK_ElGRfJm6pGajU zg1koNyJupaH9>g<5Q~Yme_lx9!Zpqk+c38P3~hb1O}HTb0~vsfGgg9bdC!19p59H& zv_7d#3N33T&z3zcp-qSZI*W$Y;*u zb>KKRKF*s7RZn1y>CO2q8t4WM@C@0EY11gPWBgq~b(&3jA4xO9)&RH1gp)jQLuZMA_qvh_?N~)fkyBBfEO{Si8oV2-7@a! z(?38p2Gu_Vb`J1 zYIHn(1?G?uf95!8FA5l)sgvfCq_7`xkt?dJI*{uUgOEQtkdg_`QF%Kzd1=~PrTo4r zs12|Haj=D+o}NjrFrBxA+a7c3O1F!M)VHx&ZEn11FUk(EtQ@X509{7gNN&(jNl;z7 zH0v^Yh(W`)5g?%}A`bSGytaTJaUp00F?MY^xE>ydSMDD5LaVrQJUYs7&kSQ{OLWDM z?q@`8^01_^2_{9VI>NM`+_G?GNeHE3Bl~J1M3i$Sh(9uoT&6kl0Q5dtv${3e!oV{d z!8*v3=*+RRSizJ>yQPM8V+e1Vmwe^cRsmIgiTYk;kS^k`IdE4!gHnXfJjW$3|661h z+1G_Lz$*AA)${j!c-G25{XQfI9T%=ZH7IMNArf_h;ED;(ldOMMCw2 z>@kYK2bO>PX@e`HG36=IF);6+0;hkCNd6hk;gKDkLvZA;58sZ9=aAKF_{!-cL*sQT zf~Yg8lvF0GV>M+MZVdk7P`?oY#0A!HocsAGjgmTHP?~o4-cZ8u72XQM4z$IoQbTTW zQZj4?oul9n+&u@(hoA6_CI&=eMvI*3V1?I&V!n8aOr_vNFAtCNsN)fo|5sB}6iD4k z-9@K2ESfoW7$jfSHq@_&!wn1TMLY}YE?9hqakeA}?#+gE^eCnS;9FLhecc6gNgi$- zQx<)J*^j);Rc-8L`uI+i?fkHqp*YR3?7AAQ#C`leGAIk{zV!mCk`QT!_tco-SaD#fyL$Dyez4J#f$Byuzh}O4jdQygbQ%HD4 zjq6LSX~I~oNy9JAW$uz|#A@~>vt@^0o6M=&hBx@~RTGE*J=&y5ZxnC+GdTXA!^Fow z_n+Mx!%IpTzxa4M^5+H`$9ex|!~QiL_?yrD_2U1t1&pyb^*0wEzp3#%|C@{d`MJL) zM1S+Se|qBahxymbFn;HMmpJ{8Jn^5O``@z+|N4plgUfJW{E`1@vBrPtpKg78MgL|e zjDPOmFVY1+9Q#YQv5LjcRr&pHwru>wEkfi7G3!Ce< zPMQ7M&3D}b)?|-u$BwE|KHNTjxX35IzSoJ-v{UHQtenRaulF)rMBn;4!lPY;&G6WvJN{fsmt<5ojYhp8D;PZ!0%G}UY0s<5{zW=d6k+SqRu zSU+nUP@FL7H%tAxq^?A>$oWclzJ!#f(pYpR zWo}^H;t}OzrF|Y@hiOOM{qQBDti18eJI<<#AivWKw76Ki6x-i@Sz3OnI!>%T?&Yen zmnQNcwd`25q2f=&zRC_7#qY%Aa4rjuo3hDw7zwMd*wsXgE=-BpCt2nExYib6)(>tm zJQdj!U3#@Q{7hhPwpWAPJ|VPvc}2W4d~*1t{@?@5dmnjbqtZCB{5W8uU6%p>M0wgx zUBx9anXX**9jr;t*1J^2eoUYyat4NnbR3P(c&%@UZ_r_p5JSqp+~B zD)hjCTKW1@GNnsge6^vD$KRep-ojdpbVC3R-Ak#$=G^wEmiSJVc zQ|qbG4q6l5$J17i9cucXr4&D%E<4e2{~BF+e9agkF!CkK#KDk0fD8K#s0ZmYmmKf; z^*uX(7^-kINKjUzeEqGnA9!|h*+#&O!uv;vos`FmUz-ghHd4G+lyku

    -ZZF}2&0dyTfeHG1VxJoZ)&u~SsmQN;u%#Z`Xd zoGD`JV0~eq6uZXBFNr-kpQ%02{H4F`opMo<=^l|&ed;L95b6OYGsNY0Hf@SXas{__ zEo$>QnS4S1VX>tf!66<#LLIwK74%oe*O+GBduDoqwx;uo2A_e5rdOM7gSd~lr4bng zF5Jp23}U&Hq5(>FwfoAbU?`9}4$2cO*Ou6_JO^Hp+YUKu?!5h#s?&ngEdsbIE_~f@ zk+V{hClJMOTQ=RTWAOeIF7qHZYR7e?yag6VQG5$}H%x}Q=?&$kwA|P-qq2=D>*`Vj zhOL34rG9zRo%q@>`7afqp&~40DMCsBAgK_Z0O(f{kl5xW1}?1tVnD~nNiq@J6e|1>m*XjA~N{| z!Hs%q?AnYMr;7FtP&OWdra$IPBjc4Opm}4fW}tk4NTKlTGoQI zEeAB-w8ETDnquRBf8^*S3>@&u46s>5v)&0Tn(5clluU;Xjw_@{%N(*4QWZoiqVqo) zo8}!6zFBJ99_n15GDEN~c(=4`guV4)*I@qhT(;6Yfb>CEc&}Ops85s>6VUqS=`hr! zNmzHI`+SujGq}www8Hx%`(BD>MP0CPEMb)su9Di7A2){yW`v#r@?7Tp{VN_3&I6%0 zU7Ny=o7@bM4Z@nY9jxJ@p%UbI+9*C`(IJTN2BC&h3vNpW#O?xydddU|wIKQBj~Gc7 zenP57o+vmq)bOyckkSbX5QD#+q;t@o6@?OCgSXa0-TZ=F!1RQ;Wtuu+8mTDs|5Bm) zf>0#VZ!OmWdH?GySCbdLlfi%BDFcxz@9T3u{g^feEn zd07bJleSH#8CmF(@ar!BqD6>;d5^|3T+CLkxak9}KV~RP&bto=7_?efZ&By~33kg&sjUn3R zjXHCf#uZ8O384Pc;{Ob{tJk~#^PPsSkYuNLd8y59MDp^|&7L(KzGQUeKrmOW9K zBfsIE;-vEC* z)TH*&{(AC2SXf{46{N+1kl;vVw>6G-l4`#Z_zeXO8fK_%5oR4J#%#m=41xue4JH)hO~Wv25*@*0(lz-i z=zse%z(F8kLROBi;tX?Sy~qr6CN0aYp$7EVJgj#DNn@< zY~1`7$fE?I6JjIkur%nUbr$dhqZ@veadP*GLnFSMQnKP%+s#6jO+db=9CWRTrY9%n;IYxUa3sUjHi)BvOK=E=p%cDAxTzfu6+MMzDu1N_9hR+iV!wXd)_m)1Uz#6I*VQO{k?#D=ji`oC9c}&gAZ#lPmTR23m{Q zdEOGkxQa-aUau4j{X}Y?RRD-(B{-yop!)iw(og7V(BS#j+*XExKs(S+EAL7=EJ!UD z)P^GKaze2oBsnlWln}2Jpw3G^NJ{I3*B37^4fEIR(*{9l zn9vGRoprD1VDIx6*^IMh6bk1lxjnm%6*#XO4p|<*5Q*upjt;83ZN#j1**vtoqW;lM zWs@J#Y()jbv)DdXI?E$}#26ZbkWL!UUUJ2!^yeBA2?s*piG(etm)XN>^V^lf-+ud5oMT#=q{0u2wZhaq9FrRQPr7>&ot5(^GPWc^qv?1MktI zhj!yEADuuSKjRcJD3#GbcOXnC_ov1cAq~pD=fdxdI*jP$)SzB%ZtvbbtS#)!!QTBT zF1zDi^XRamt9<->KPnwnKAj;Z>74Z?S@C3pDXWY+bef!e@XtaZAt>jHVNy~srI%c5 zL6j2Q>(SBCK}as7d$35K?bq3N?)RpFJj)a}Y}9&$j|U080l{D>IIyZgFWi%a>P}lG z#Q$g#j+HQ~c$pc~qSWpiWgchDe?Ztg;H$Y^cu;?iPRC0nyN$$=5~?<7p(EV>gPN~n zbn`A77^qfxmNSYQO1^0=7oXZ>%}V1|RZlE+9}4WD!B(byi|=GBER_a@i1Zv1Y6RL**C*s39*6Q2Kj85QI;B9I%_;eUk1{?*FR^a%=O zZxu~nS!~u7ww|$L?G+p#B}iK~*+t-xh+uba+{;MwwA@^J?w-Ie1+!83NappW?@mhD zIyST96bu#e>|1>$Qhv5sk@wkSN)LV>`&>0!JapIgc$~uy;)Y2(AfZY_FrR<4KFI18a0QCcW8nL)a zYkf2q`q?Sa(05!iV)*f`?dbmpkoY+<>n+1L*2Wk8$ zikAj&Lka%Pln_SH6+l?JB=-3hux=${Kl_2gp!yiPMmC9}!i?=UVJ&g2s2y3GNPixQ zCo!*Xm?RJ0ROgeqcIz|6&zh6o&ZH}spRFFM;7)&|wV?0DLd6VZChmkd3dxiBdS88X ztkVm+@7Z+!@_;z#IxC(2`h@flF&Z_t#sYmZ^*Yi_Rl?i`+|htw$o!#XPchllUxKpt zOAq8XgS`fVb&4CbA#2G#AS7u)G)?E)KZKn+4^m_|#LXVWN(_n|5BuFa~YxLs<+3w=vg~g-b-`iWpJuEdv_Sg9@Uxnp~(bzk5 zBzvD7`+lOKQ=F&p>Ce+X-aky936>Pn=B#P`LK`6c; z17bQIByS>VSCod19XHz}!geiq+O~v5O(J{Jz+y_SeNb}%gMoY^i|F9C5qH{CY12l? z|Ad6s1Mf~!R|Tnhm)&zRRdoV9I5xjug_i6b!kHORIcu4cl#s*~Cf|;7`wRV%p8n8#q#q@ z5B`|zH`E7RiaLa3x%8BtmW`%;Vs*#}$pmC+{6mDmD`Y?x&k6lQ$% z!{aZ6Irw9W7_%AsKdd@QJr)5FeV}~`S0x&^R}RB9eH7g*Enlmt_u7CzBE&gpd{cHc zkUzXUMfAZVONay~5^TA1Vf1Bo5q9kFiQ5Lc8GLg0`0TFc(r5Q7WSVOQX7=XoTqPOX zRQ@JCNA>p!R@3wL_%pRq{e$m@MEaztIC}A&dE$kxa=!^fI1#3S8LI>Y@F4nPNFW7X z-a4>%UcPv70Ki>VcD6D>?()pq?Jf_z|FOs<#Q5My%(B6Jcf?PQMJ<(42VHBaM#~x1 z>Gsid3$F7)(jAYSYlGbsvq)bVnrq+ai?t{@3>3EMcRjeHdHc>VBE5>o{SKr0TU(lM z-;|44%IrR!K-(V=E*NWiMh-FqB@5zcJzVBg=+XEincjhQR@d6_n;b2Y(h-Isx|XSJ z%nl93!I{)i=pXfo-xHJpC4!memG=o*dI?fD0%v{b`2ZRe`SW|i_urgDls7?$dkLY` zFSkLt_23AZe!lsHi{BgU#`#@g;)_O2t&4(9X*TZ`$DnCjN3lzaOYY7EqyI{wg!zvK z2>oaHC(TT)w_!z;7mLG>`k;^NWpor)vLVpM2tp<;n?_(a%4eSLH%u{+fzQSWVSm|e z13``iF{dgxwGpWIe-X5QgkAL2l5hC7bsGhHxDpvR1XHJVHhdZIXN&fIHpY^55ZdB! zM2EZ_4IL5ha!KY-5)9Z@8icAy8w}Yr$r{G5!(y`t?%{0LtW^RLgD6B|i1EbdO8k}q zud3)x!_w^+59jS{dPCYoK<<)rMIN`7$PidknH9X5L_mT!6Fb&UbeJUNQa^Z(8XId7 zK<(0Gpx?S_PKtnJukr8SHsG}C08bE^r8j1s;IOkj5;yo(y8x02GpbwnN~8yYfPaB#&e{ zum>JJ?Zj0MH@+f1wD+Hi-GBrD&HV@BG~RMal-B^Ky8Iv=f|tJewsyaaAR(X|;) zPptc!aum!$!*>i>J@nJy+5_o!cgdJ-js>ZMS&c zUE(mozlW|qIVzoN}Pu3pj8YZ$?5ZwkYtXL#ch zz1Lxp$n8Rqmdd%393L$sro;TwOwwitVdhJN_5JK9uaz@BB z2nYdhXyeKYzdC|ds&;jqt8^kPcAkCMg-?hZ9x55+zZ!f7(jA|1n+X{0j zgn-~3Jq&)ZoGUT&kPym5SZ9K4MjMTzBn?;|ATx?uN2+Q}OA#wG_md|hQt*#^f{SeF=DyBzZDfdhv6Z(Lub3Qg9PdBzzGh3^4NLwWZ`^}qRc~xjA59> zc3{y4T`~9Q6YU9~8x4vCVTm93^|}yxzPxg1AtU6-9ADv0*fol-7`PL@eSQEh06}F} zZ7`PmnGALyX>SGJS|HGN_=#7AowI64$d=&rVj1*JO|2L2E-UWG+$`4Y<@TKXCtZMp zZv*vS3wf?9FHx3QUZ&u^<;fy@s5O{=S*+sz{LJZJVBpg5zWu;+-oyj^CJG41d1&hs zNX`^M5m~N7fELKcFTYarpqo3f=An2>6RjVi*Fjf^Kdwj73%UtfuEEIHB+4uC2rIv?B}Y)kH%$*K8^Lc3C~j}Z6Vje?ThYl3El5=& zf>6hZ;v@`{gV-gnAWCfu;cQ86DlkO}PK=x>Kugv2@OZ2X5t%T1mY7cke2EtUy8jph z`wytmAVxBQmG6#kiQ7bsBp{|#bqLsRS^qz|G6IG0Hh- z2*b@8>3YLz&#f*|Nox~L^&hamO=}HfYj22{aid{QB}eU2q=D=>7c<>gKs%CgL91V} zwA%I+kz*9*DEe>I5v0c)%D2}Hrb_?Lw(+#0F&!>b+cTKaZ8qALetSB&83Zq#`QixL8AUV--zqrok4IISA61Z9+VKr1UbhtE9zILu8$6!Jqdp0KGA__ z=}6cDAxYX!UCT@4r-r0s0T%`=4;QF2Lzoo}!96VYbN}Q%mQ54Y3!OuDb3lx)Zs7x_ zs70O%PVLJ2*{8oRLbnXrZU4%cOIXiYXk?F@j+ED>XL}gt3aO??V#LR-`h}eY9@^-zjGYip& zl$92ecse+2%U6XNDp~habH)%0KJZa+Lwu4gWDuq)o50yW+7Ony-W{c@#69_jzs^By zbhT260*@9dw_Rw%=ZKlBmAFicR@o&FO~Kqvcla?uQ8Pcbu`cm~Qr+e?Mx~JzKHN0f zX0JhpH;67)W@z=Vouk^=Fa2EyIrcwGJ>LxPhy{K=3P!e(H?BZ=m6troVvqW^v9y4D z3*8LIYpRSHmLNQ))K%>7Y)CpeEM=^}{KU}U9E)~t&SabD5)sDDxQL_i;GA>g4z>Lw(1i=oX>Iqsi%*P17&k)^&QBkrx?1cyLvZ#!WYLb}PxN|2pCcE^WTJq*}pZOt#3w zLduHbGJPVY>7l|uqWs>zVfn@D+b*2y`*W$Q-MA^s?Zw<3s|%W=3fp`8HEZ7e>m>eQ z`l{Kp*)NOpuTJn>YAJZ+xkBOa&~<2RZ${RFLC(=pTx(6mbjz}Xw&nb#uS?Z0q{AZ? zwK?74KB^A8JtO>7Rvmq}n}>f<+1{YwT92HFK@;!M!=JFX%ql3=q3OUbQPbPMTR16` uHPZ50)E({ck8C%roN#!A-;TdRWUn1-8vLIKDkr|8sPS0qwMMo&X#fA)xZc Date: Wed, 26 Jun 2024 14:15:45 +0200 Subject: [PATCH 268/860] 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 269/860] 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 270/860] 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 271/860] 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 272/860] 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 616932aa47c2e31db6990c9970f6f9fac62a079d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jun 2024 21:50:24 +0000 Subject: [PATCH 273/860] fix(deps): update aws-sdk-js-v3 monorepo Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 2164 ++++++++++++++++++++++++++++------------------------- 1 file changed, 1127 insertions(+), 1037 deletions(-) diff --git a/yarn.lock b/yarn.lock index 912220ac86..08218f6ee9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -385,69 +385,58 @@ __metadata: languageName: node linkType: hard -"@aws-crypto/crc32c@npm:3.0.0": - version: 3.0.0 - resolution: "@aws-crypto/crc32c@npm:3.0.0" +"@aws-crypto/crc32@npm:5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/crc32@npm:5.2.0" dependencies: - "@aws-crypto/util": ^3.0.0 + "@aws-crypto/util": ^5.2.0 "@aws-sdk/types": ^3.222.0 - tslib: ^1.11.1 - checksum: 0a116b5d1c5b09a3dde65aab04a07b32f543e87b68f2d175081e3f4a1a17502343f223d691dd883ace1ddce65cd40093673e7c7415dcd99062202ba87ffb4038 + tslib: ^2.6.2 + checksum: 1ddf7ec3fccf106205ff2476d90ae1d6625eabd47752f689c761b71e41fe451962b7a1c9ed25fe54e17dd747a62fbf4de06030fe56fe625f95285f6f70b96c57 languageName: node linkType: hard -"@aws-crypto/ie11-detection@npm:^3.0.0": - version: 3.0.0 - resolution: "@aws-crypto/ie11-detection@npm:3.0.0" +"@aws-crypto/crc32c@npm:5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/crc32c@npm:5.2.0" dependencies: - tslib: ^1.11.1 - checksum: 299b2ddd46eddac1f2d54d91386ceb37af81aef8a800669281c73d634ed17fd855dcfb8b3157f2879344b93a2666a6d602550eb84b71e4d7868100ad6da8f803 + "@aws-crypto/util": ^5.2.0 + "@aws-sdk/types": ^3.222.0 + tslib: ^2.6.2 + checksum: 0b399de8607c59e1e46c05d2b24a16b56d507944fdac925c611f0ba7302f5555c098139806d7da1ebef1f89bf4e4b5d4dec74d4809ce0f18238b72072065effe languageName: node linkType: hard -"@aws-crypto/sha1-browser@npm:3.0.0": - version: 3.0.0 - resolution: "@aws-crypto/sha1-browser@npm:3.0.0" +"@aws-crypto/sha1-browser@npm:5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/sha1-browser@npm:5.2.0" dependencies: - "@aws-crypto/ie11-detection": ^3.0.0 - "@aws-crypto/supports-web-crypto": ^3.0.0 - "@aws-crypto/util": ^3.0.0 + "@aws-crypto/supports-web-crypto": ^5.2.0 + "@aws-crypto/util": ^5.2.0 "@aws-sdk/types": ^3.222.0 "@aws-sdk/util-locate-window": ^3.0.0 - "@aws-sdk/util-utf8-browser": ^3.0.0 - tslib: ^1.11.1 - checksum: 78c379e105a0c4e7b2ed745dffd8f55054d7dde8b350b61de682bbc3cd081a50e2f87861954fa9cd53c7ea711ebca1ca0137b14cb36483efc971f60f573cf129 + "@smithy/util-utf8": ^2.0.0 + tslib: ^2.6.2 + checksum: 8b04af601d945c5ef0f5f733b55681edc95b81c02ce5067b57f1eb4ee718e45485cf9aeeb7a84da9131656d09e1c4bc78040ec759f557a46703422d8df098d59 languageName: node linkType: hard -"@aws-crypto/sha256-browser@npm:3.0.0": - version: 3.0.0 - resolution: "@aws-crypto/sha256-browser@npm:3.0.0" +"@aws-crypto/sha256-browser@npm:5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/sha256-browser@npm:5.2.0" dependencies: - "@aws-crypto/ie11-detection": ^3.0.0 - "@aws-crypto/sha256-js": ^3.0.0 - "@aws-crypto/supports-web-crypto": ^3.0.0 - "@aws-crypto/util": ^3.0.0 + "@aws-crypto/sha256-js": ^5.2.0 + "@aws-crypto/supports-web-crypto": ^5.2.0 + "@aws-crypto/util": ^5.2.0 "@aws-sdk/types": ^3.222.0 "@aws-sdk/util-locate-window": ^3.0.0 - "@aws-sdk/util-utf8-browser": ^3.0.0 - tslib: ^1.11.1 - checksum: ca89456bf508db2e08060a7f656460db97ac9a15b11e39d6fa7665e2b156508a1758695bff8e82d0a00178d6ac5c36f35eb4bcfac2e48621265224ca14a19bd2 + "@smithy/util-utf8": ^2.0.0 + tslib: ^2.6.2 + checksum: 773f12f2026d82a6bb4a23a8f491894a6d32525bd9b8bfbc12896526cf11882a7607a671c478c45f9cd7d6ba1caaed48a62b67c6f725244bd83a1275108f46c7 languageName: node linkType: hard -"@aws-crypto/sha256-js@npm:3.0.0, @aws-crypto/sha256-js@npm:^3.0.0": - version: 3.0.0 - resolution: "@aws-crypto/sha256-js@npm:3.0.0" - dependencies: - "@aws-crypto/util": ^3.0.0 - "@aws-sdk/types": ^3.222.0 - tslib: ^1.11.1 - checksum: 644ded32ea310237811afae873d3c7320739cb6f6cc39dced9c94801379e68e5ee2cca0c34f0384793fa9e750a7e0a5e2468f95754bd08e6fd72ab833c8fe23c - languageName: node - linkType: hard - -"@aws-crypto/sha256-js@npm:^5.0.0": +"@aws-crypto/sha256-js@npm:5.2.0, @aws-crypto/sha256-js@npm:^5.0.0, @aws-crypto/sha256-js@npm:^5.2.0": version: 5.2.0 resolution: "@aws-crypto/sha256-js@npm:5.2.0" dependencies: @@ -458,12 +447,12 @@ __metadata: languageName: node linkType: hard -"@aws-crypto/supports-web-crypto@npm:^3.0.0": - version: 3.0.0 - resolution: "@aws-crypto/supports-web-crypto@npm:3.0.0" +"@aws-crypto/supports-web-crypto@npm:^5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/supports-web-crypto@npm:5.2.0" dependencies: - tslib: ^1.11.1 - checksum: 35479a1558db9e9a521df6877a99f95670e972c602f2a0349303477e5d638a5baf569fb037c853710e382086e6fd77e8ed58d3fb9b49f6e1186a9d26ce7be006 + tslib: ^2.6.2 + checksum: 6ffc21de48b2b2c3e918193101d7e8fe949d47b37688892e1c39eaedaa938be80c0f404fe1c874c30cce16781026777a53bf47d5d90143ca91d0feb7c4a6f830 languageName: node linkType: hard @@ -500,665 +489,674 @@ __metadata: linkType: hard "@aws-sdk/client-codecommit@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/client-codecommit@npm:3.556.0" + version: 3.600.0 + resolution: "@aws-sdk/client-codecommit@npm:3.600.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: 09a7393ba36cf0eaf527041580e468b62346634768ee1ced243e5e894d6a532f96332642ddc1965c9e2078cbe4183c84bc6003a427a05e6ea781ceff5c143e0d + checksum: 1a8197ffcf74b27a4b6159d8b4923db0f5c27b3d5daacb321ef956c49b0250800ce904c1c03264c67366c14244a8ba7a067849700b382979da19f7bc4c20a3fd languageName: node linkType: hard -"@aws-sdk/client-cognito-identity@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/client-cognito-identity@npm:3.556.0" +"@aws-sdk/client-cognito-identity@npm:3.600.0": + version: 3.600.0 + resolution: "@aws-sdk/client-cognito-identity@npm:3.600.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 964ee562d41df0fc3d71a739ef86846dddbfa8742df74831926dd629de0111ace69faed4869d9b7a50cd5eb8d2c1ac09da2126b7071e9d69f8ba8e8d85d24323 + checksum: ad01c387061da6d46767e209f3d422281e6af97d60ed61af687980990c7600ecbd88e2f430d975f029648d4475bf84234f710f4099edd2d61f90fef3444ee4a0 languageName: node linkType: hard "@aws-sdk/client-eks@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/client-eks@npm:3.556.0" + version: 3.605.0 + resolution: "@aws-sdk/client-eks@npm:3.605.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 - "@smithy/util-waiter": ^2.2.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 + "@smithy/util-waiter": ^3.0.1 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: c36a0f23d3f01ed9fcbeec286b5e919cacc2ecb0bb3e880844e9b84018d81935c4b8f3dc33a3392c808a6e001659f5ca0c99889d830491c48040b9df3d474cc8 + checksum: 6cd87756d631fd18b12d21a89a938612ba17446cdc1de06c3c3a0ee488ffd8c9de4af3d27567524eb0e17155d423394e374002cb5a45d4376df6d82255abe870 languageName: node linkType: hard "@aws-sdk/client-organizations@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/client-organizations@npm:3.556.0" + version: 3.600.0 + resolution: "@aws-sdk/client-organizations@npm:3.600.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: e747d1f2f75a9985944765ac920408bffe5fc79dfb700c56b1633fec4e6f480b9568e30f72a6c80f09dcb7998480f158fa5c40646e8af4fed4a68e694d78c4f8 + checksum: b403a51e298fec8ec93553ac8a22a452408b0634b3a01d6c61ce271d7af69b1cef8907a9dce31fad79fa2cfc01fd6912d848e9b656b7a16f973e986b00bd727c languageName: node linkType: hard "@aws-sdk/client-s3@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/client-s3@npm:3.556.0" + version: 3.600.0 + resolution: "@aws-sdk/client-s3@npm:3.600.0" dependencies: - "@aws-crypto/sha1-browser": 3.0.0 - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-bucket-endpoint": 3.535.0 - "@aws-sdk/middleware-expect-continue": 3.535.0 - "@aws-sdk/middleware-flexible-checksums": 3.535.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-location-constraint": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-sdk-s3": 3.556.0 - "@aws-sdk/middleware-signing": 3.556.0 - "@aws-sdk/middleware-ssec": 3.537.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/signature-v4-multi-region": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@aws-sdk/xml-builder": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/eventstream-serde-browser": ^2.2.0 - "@smithy/eventstream-serde-config-resolver": ^2.2.0 - "@smithy/eventstream-serde-node": ^2.2.0 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-blob-browser": ^2.2.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/hash-stream-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/md5-js": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-stream": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 - "@smithy/util-waiter": ^2.2.0 + "@aws-crypto/sha1-browser": 5.2.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-bucket-endpoint": 3.598.0 + "@aws-sdk/middleware-expect-continue": 3.598.0 + "@aws-sdk/middleware-flexible-checksums": 3.598.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-location-constraint": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-sdk-s3": 3.598.0 + "@aws-sdk/middleware-signing": 3.598.0 + "@aws-sdk/middleware-ssec": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/signature-v4-multi-region": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@aws-sdk/xml-builder": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/eventstream-serde-browser": ^3.0.2 + "@smithy/eventstream-serde-config-resolver": ^3.0.1 + "@smithy/eventstream-serde-node": ^3.0.2 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-blob-browser": ^3.1.0 + "@smithy/hash-node": ^3.0.1 + "@smithy/hash-stream-node": ^3.1.0 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/md5-js": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-stream": ^3.0.2 + "@smithy/util-utf8": ^3.0.0 + "@smithy/util-waiter": ^3.0.1 tslib: ^2.6.2 - checksum: e5b04013a9270b438b196ccf60bedba14187ee059fbd3fd42a8bac927c7935226ba031c1a5312befa6e37e4ea8cd075fe28b8b524fe51b5b372bf5543dd46216 + checksum: be9940ac1a9bff2e8efbf6f0ac782b0bcd66ab229639dc46d60aa71e041b3ef16a327e37c92397691a16c982cf5e529ab2ffd60351a9d9730bf4947bb391ced4 languageName: node linkType: hard "@aws-sdk/client-ses@npm:^3.550.0": - version: 3.556.0 - resolution: "@aws-sdk/client-ses@npm:3.556.0" + version: 3.600.0 + resolution: "@aws-sdk/client-ses@npm:3.600.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 - "@smithy/util-waiter": ^2.2.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 + "@smithy/util-waiter": ^3.0.1 tslib: ^2.6.2 - checksum: 913108e79061185faae51711b121df99da624f988f530af23c3e4270299be60771be83f507dc8ed4af4051765077ea038edab19e4d0d32e159c4e67faf5fc9f8 + checksum: f0c042db4e20b8165f7da42ba2026ee6c32944c10c6a3508c021efbc0a3474fd0ef888367db47f54dc89a6bbad482858b0c816f6d3ec4ac84bfc156d315b2381 languageName: node linkType: hard "@aws-sdk/client-sqs@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/client-sqs@npm:3.556.0" + version: 3.600.0 + resolution: "@aws-sdk/client-sqs@npm:3.600.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-sdk-sqs": 3.552.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/md5-js": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-sdk-sqs": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/md5-js": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: fe14caaffe9115b430d7c89895b193b2415532862b6cb70918ea0790f01017ca4bbf998ed221bf7fb4285b7eb6090c156bca4c8ccf49f61f2c34f96fd57e7ed4 + checksum: e0ec11d0d89539ae1964cc2f0655af7367c0c43153ab16fe9542e303cd1b69c5f0e9f3d912c52ff7bbfc5f557733d52e187e72563f0bfed3a21ed6249ae37c8a languageName: node linkType: hard -"@aws-sdk/client-sso-oidc@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/client-sso-oidc@npm:3.556.0" +"@aws-sdk/client-sso-oidc@npm:3.600.0": + version: 3.600.0 + resolution: "@aws-sdk/client-sso-oidc@npm:3.600.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - peerDependencies: - "@aws-sdk/credential-provider-node": ^3.556.0 - checksum: d932569016b811e14bd977e2e198556e3e4bf156108b098eb8850f83486cf361e23e17cc2fbae2ae7ebb1c2268f312a64c90dafb9f19e8dd6e9a817397e79552 + checksum: ef7a40ce69de30b25a8a7a5ee035f17e87edc1060c128b3b50f30f19b681aaa7b99b564ffc348cd74fe0e1079bd46087a6784674266d743c45564bcd4d5221b3 languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/client-sso@npm:3.556.0" +"@aws-sdk/client-sso@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/client-sso@npm:3.598.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: bf0f2d449983c650e25befbee80dd48508464c1814e5b412a8f5e725e88e0764ac75a1b959df509c746b638dbbb571f51617be4c02f7b0ef8185c045255f6c52 + checksum: b570f54643ac0ab0f300bf074e77c2fbba70206a11d2aed1f6ecd361027f2f6a1d62719627e905bcb44dd73d481a29ef5a70878c676386afe2a133f479a445d4 languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.556.0, @aws-sdk/client-sts@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/client-sts@npm:3.556.0" +"@aws-sdk/client-sts@npm:3.600.0, @aws-sdk/client-sts@npm:^3.350.0": + version: 3.600.0 + resolution: "@aws-sdk/client-sts@npm:3.600.0" dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@smithy/config-resolver": ^2.2.0 - "@smithy/core": ^1.4.2 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/hash-node": ^2.2.0 - "@smithy/invalid-dependency": ^2.2.0 - "@smithy/middleware-content-length": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-body-length-browser": ^2.2.0 - "@smithy/util-body-length-node": ^2.3.0 - "@smithy/util-defaults-mode-browser": ^2.2.1 - "@smithy/util-defaults-mode-node": ^2.3.1 - "@smithy/util-endpoints": ^1.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.600.0 + "@aws-sdk/core": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/middleware-host-header": 3.598.0 + "@aws-sdk/middleware-logger": 3.598.0 + "@aws-sdk/middleware-recursion-detection": 3.598.0 + "@aws-sdk/middleware-user-agent": 3.598.0 + "@aws-sdk/region-config-resolver": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@aws-sdk/util-user-agent-browser": 3.598.0 + "@aws-sdk/util-user-agent-node": 3.598.0 + "@smithy/config-resolver": ^3.0.2 + "@smithy/core": ^2.2.1 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/hash-node": ^3.0.1 + "@smithy/invalid-dependency": ^3.0.1 + "@smithy/middleware-content-length": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/middleware-retry": ^3.0.4 + "@smithy/middleware-serde": ^3.0.1 + "@smithy/middleware-stack": ^3.0.1 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/url-parser": ^3.0.1 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.4 + "@smithy/util-defaults-mode-node": ^3.0.4 + "@smithy/util-endpoints": ^2.0.2 + "@smithy/util-middleware": ^3.0.1 + "@smithy/util-retry": ^3.0.1 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - peerDependencies: - "@aws-sdk/credential-provider-node": ^3.556.0 - checksum: 81ce40440de0c3012b6e21d7f9b748bc46982e72ffaccc763efeed34d79eee519ed9a95e2cb37b2e411460cced2897f409d90e42a5b012344358839c717fa435 + checksum: 47d6d145d481c8dc285b68baccf36ab76b92ed1fbf5a58a0900bbe913a7caf3eddc84414428b013e58c91242e7ffd5a55b0620217dc295c75c2729ccb89b9ae8 languageName: node linkType: hard -"@aws-sdk/core@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/core@npm:3.556.0" +"@aws-sdk/core@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/core@npm:3.598.0" dependencies: - "@smithy/core": ^1.4.2 - "@smithy/protocol-http": ^3.3.0 - "@smithy/signature-v4": ^2.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 + "@smithy/core": ^2.2.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/signature-v4": ^3.1.0 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 fast-xml-parser: 4.2.5 tslib: ^2.6.2 - checksum: 9b446f0939f8573289b598282194aeff81b3e8c9aa76b29d6e865fe40f38b301f041fab39d565f975ed6e8a3ba4d4b9b43444aaab7dbf2c7ea84e67d370a2695 + checksum: e58944a6571808b53d21f012b9671ffec597d2a826a9c0f1fbcbe160189a3c47f5b4671ac92b7437c349f19b8a8df7e12255c57795ab0224c318ed69a0d23229 languageName: node linkType: hard -"@aws-sdk/credential-provider-cognito-identity@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.556.0" +"@aws-sdk/credential-provider-cognito-identity@npm:3.600.0": + version: 3.600.0 + resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.600.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/client-cognito-identity": 3.600.0 + "@aws-sdk/types": 3.598.0 + "@smithy/property-provider": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 4c66b780f9f8c3e5df9d5e397069e0bbd31596bfb93b5ac76baa39cb0ef7bebc848a879b940dbcdda7c40cb78beeb46e0b10fab94e71ea317e0512e49c9b6f80 + checksum: 9e7e325fde26192fbd7f542ad0ff69d193b5edb65b0361cdeb13f538b1b563de999e82da34493921351ea599643c4884bd17fdc16eba423d3343e681f346072f languageName: node linkType: hard -"@aws-sdk/credential-provider-env@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/credential-provider-env@npm:3.535.0" +"@aws-sdk/credential-provider-env@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/property-provider": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: ec7d011051d69643efd26fe7f3767b1301c6e6bdba12640dad542b60efb2b5fe31df01f8137703d814cf857a69485cc928d0de49ab56c5d05f79815dce19bdbf + checksum: 517f06dd47b7aa4c8d5a9fe82698150237c28c46ed9f82cd1d92d1453690b9d6139b65519d92dea611d319c4418fe4540e7d52c03d3897e7e471731fb0156afb languageName: node linkType: hard -"@aws-sdk/credential-provider-http@npm:3.552.0": - version: 3.552.0 - resolution: "@aws-sdk/credential-provider-http@npm:3.552.0" +"@aws-sdk/credential-provider-http@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/credential-provider-http@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/util-stream": ^2.2.0 + "@aws-sdk/types": 3.598.0 + "@smithy/fetch-http-handler": ^3.0.2 + "@smithy/node-http-handler": ^3.0.1 + "@smithy/property-provider": ^3.1.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/util-stream": ^3.0.2 tslib: ^2.6.2 - checksum: 86be07b2a0c73b5c1140557e00b08c091303da1908ff40a29bcc69b73bf4ad175a5ad945e0d45d5c76b02bee3f15a947abb18838b2771ad71feb795a5309a446 + checksum: e2f6208491a6e58b7ac7368c2247dee55080be740511ded01cc3454920ef29d0b7712930571651a8d0ec2aea4e0a107c7d5dd6ecd01bd4de3c264c54e32959b3 languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.556.0" +"@aws-sdk/credential-provider-ini@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.598.0" dependencies: - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/credential-provider-env": 3.535.0 - "@aws-sdk/credential-provider-process": 3.535.0 - "@aws-sdk/credential-provider-sso": 3.556.0 - "@aws-sdk/credential-provider-web-identity": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/credential-provider-imds": ^2.3.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/shared-ini-file-loader": ^2.4.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/credential-provider-env": 3.598.0 + "@aws-sdk/credential-provider-http": 3.598.0 + "@aws-sdk/credential-provider-process": 3.598.0 + "@aws-sdk/credential-provider-sso": 3.598.0 + "@aws-sdk/credential-provider-web-identity": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@smithy/credential-provider-imds": ^3.1.1 + "@smithy/property-provider": ^3.1.1 + "@smithy/shared-ini-file-loader": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 24b7dc1349f80090455bde95856955aef824752bff8b91dbad1dea784dc03b48b9671650aa2002de8427bd1df832c33be52b5bf157ad2759ad65a6d37247e339 + peerDependencies: + "@aws-sdk/client-sts": ^3.598.0 + checksum: 9fab1e9c312e20150c96daf15e0347b79f0589cc44eb299c15e80c7d5380e8966805fa8893d3c906f99b7eb3c0f872f0795415f75921204580a30d869dd87f54 languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.556.0, @aws-sdk/credential-provider-node@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.556.0" +"@aws-sdk/credential-provider-node@npm:3.600.0, @aws-sdk/credential-provider-node@npm:^3.350.0": + version: 3.600.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.600.0" dependencies: - "@aws-sdk/credential-provider-env": 3.535.0 - "@aws-sdk/credential-provider-http": 3.552.0 - "@aws-sdk/credential-provider-ini": 3.556.0 - "@aws-sdk/credential-provider-process": 3.535.0 - "@aws-sdk/credential-provider-sso": 3.556.0 - "@aws-sdk/credential-provider-web-identity": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/credential-provider-imds": ^2.3.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/shared-ini-file-loader": ^2.4.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/credential-provider-env": 3.598.0 + "@aws-sdk/credential-provider-http": 3.598.0 + "@aws-sdk/credential-provider-ini": 3.598.0 + "@aws-sdk/credential-provider-process": 3.598.0 + "@aws-sdk/credential-provider-sso": 3.598.0 + "@aws-sdk/credential-provider-web-identity": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@smithy/credential-provider-imds": ^3.1.1 + "@smithy/property-provider": ^3.1.1 + "@smithy/shared-ini-file-loader": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: c4b83c36426941caff81a25393eec101cf2d21264c29c69e5a7a940ae8af1f4b2a8f0a26f47c2294a32f381d53eed9ba2dc2cbbcd053585aa9016acb79e98ad8 + checksum: 480c7c36a8558667a25617e6f7f2292b4362b0e894bc204ce62f565dc8e8cc46c713dc04621321336ce715b493590b3b854b33dc6d5123ed39a17643158d94fc languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.535.0" +"@aws-sdk/credential-provider-process@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/shared-ini-file-loader": ^2.4.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/property-provider": ^3.1.1 + "@smithy/shared-ini-file-loader": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: af5fad70513e8d0bc10013f220588e45e83d488e0780873d7e76bf5b7099e70c9b4e49b6409d16add64ae212c53a472b12a2178e8bafd7878fdf121d6e2fd112 + checksum: cd1f0dbbc38b137a0e9c2cfa9bb9e55eed1da5166e13576295205d276ab313e9d4a2f97a566d576abc85c6f4e9e84ad676ca5c32f90de17e027d6a1372fb00e6 languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.556.0" +"@aws-sdk/credential-provider-sso@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.598.0" dependencies: - "@aws-sdk/client-sso": 3.556.0 - "@aws-sdk/token-providers": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/shared-ini-file-loader": ^2.4.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/client-sso": 3.598.0 + "@aws-sdk/token-providers": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@smithy/property-provider": ^3.1.1 + "@smithy/shared-ini-file-loader": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: ea6c9bd7f183abedf79ff7959fdc31c16cb250afece2304d3005343aae4a203d04f2421ac1dd0a815a6d1823c721b277449d0ab27dc17fe8c75b211e44a31667 + checksum: 16828609b9ac17772eecd89deb9ac9b98a1decad42ca1f8cf6a57e6873eeb3563db00bfb67684cbb08108d5ee6b8f98ec23047d7f6750cb67c1342cd8b96ac1c languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.556.0" +"@aws-sdk/credential-provider-web-identity@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.598.0" dependencies: - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/property-provider": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 79d3277db07130b201b5788a76e8a71c2816be1e190ce7f96d174c2c8153fdcfb6adbf17575d8fd5c928452327a37872f18a48e563805997247bdc3cda2b9cac + peerDependencies: + "@aws-sdk/client-sts": ^3.598.0 + checksum: e62352ae7f408ae8969d22fd42a502ec078536952be1253f184bf96c57f3c88589fd431762b2300b494159df4eb4af975358645772ac36f2cc722c86a88ff85e languageName: node linkType: hard "@aws-sdk/credential-providers@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-providers@npm:3.556.0" + version: 3.600.0 + resolution: "@aws-sdk/credential-providers@npm:3.600.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.556.0 - "@aws-sdk/client-sso": 3.556.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/credential-provider-cognito-identity": 3.556.0 - "@aws-sdk/credential-provider-env": 3.535.0 - "@aws-sdk/credential-provider-http": 3.552.0 - "@aws-sdk/credential-provider-ini": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/credential-provider-process": 3.535.0 - "@aws-sdk/credential-provider-sso": 3.556.0 - "@aws-sdk/credential-provider-web-identity": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/credential-provider-imds": ^2.3.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/client-cognito-identity": 3.600.0 + "@aws-sdk/client-sso": 3.598.0 + "@aws-sdk/client-sts": 3.600.0 + "@aws-sdk/credential-provider-cognito-identity": 3.600.0 + "@aws-sdk/credential-provider-env": 3.598.0 + "@aws-sdk/credential-provider-http": 3.598.0 + "@aws-sdk/credential-provider-ini": 3.598.0 + "@aws-sdk/credential-provider-node": 3.600.0 + "@aws-sdk/credential-provider-process": 3.598.0 + "@aws-sdk/credential-provider-sso": 3.598.0 + "@aws-sdk/credential-provider-web-identity": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@smithy/credential-provider-imds": ^3.1.1 + "@smithy/property-provider": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 6d00b6ab7fbd0e0ca83ecd2823b446290be20d68f7c2b26128b8f678ab9d6e0f7fb423adf94bb12903abdeb324b4aa7ce8dd81e0b17f5b3322f6b14e634552e0 + checksum: d957d851a9d4aba30e941c12515ce08fda66cadf2623fa329a2f651e2229e901a7845b139cd15404c8a714985e9b358747f1a8aacf0951e9b05331c5ae92af7c languageName: node linkType: hard @@ -1184,34 +1182,34 @@ __metadata: linkType: hard "@aws-sdk/lib-storage@npm:^3.350.0": - version: 3.556.0 - resolution: "@aws-sdk/lib-storage@npm:3.556.0" + version: 3.600.0 + resolution: "@aws-sdk/lib-storage@npm:3.600.0" dependencies: - "@smithy/abort-controller": ^2.2.0 - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/smithy-client": ^2.5.1 + "@smithy/abort-controller": ^3.0.1 + "@smithy/middleware-endpoint": ^3.0.2 + "@smithy/smithy-client": ^3.1.2 buffer: 5.6.0 events: 3.3.0 stream-browserify: 3.0.0 tslib: ^2.6.2 peerDependencies: - "@aws-sdk/client-s3": ^3.0.0 - checksum: 361e87ce38f566e7ffe0da2bd436bfda5dfce1c9e4f86f4fbab9e157ba24a47e169824dd9723f02eab8cd682b381a765453bd8d4c5fa0ae3c5273ff6d3a166e5 + "@aws-sdk/client-s3": ^3.600.0 + checksum: 3fc04712f61289ac47f9502f0f33351a50e581d7999398575e84713750c77261b20ef8ac4f0a68514737c9950b313a563752b6856f63acaff23d128a4b4a9f4b languageName: node linkType: hard -"@aws-sdk/middleware-bucket-endpoint@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.535.0" +"@aws-sdk/middleware-bucket-endpoint@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-arn-parser": 3.535.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 - "@smithy/util-config-provider": ^2.3.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-arn-parser": 3.568.0 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/types": ^3.1.0 + "@smithy/util-config-provider": ^3.0.0 tslib: ^2.6.2 - checksum: d72dfd197dc9aa1ed8ea3de6fb0a18363688fa8e18f6a9d01cb2f425087c5b72aa4bfd0955715c84da86adf9a46029755cff55a02a6ffbf4459009982a5a5415 + checksum: 45a4adc3427a70f7129675439c9396073dc418e9e5ede4acd0dc0620d76610e8adf3f1c863120f7714bc67053a194289ac55ce6814a79960c4746cbd45f7116f languageName: node linkType: hard @@ -1228,108 +1226,108 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-expect-continue@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-expect-continue@npm:3.535.0" +"@aws-sdk/middleware-expect-continue@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-expect-continue@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/protocol-http": ^4.0.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: fdac9bc59833ca9688155f115f85c31f690df5ef690e9a8921b94b87c4faac3eb3ff10641699822faaaf9a6cc4ce4c67e693a7b4befe8baf8138a9d276d6714d + checksum: 1038945711d48d661cbf21343fd78968240f43b18f5b7fade7e41a7bf5308a65f37859f2b349e5fb038dded0136e0ea734e38e52085178b6a546a6ac48c630e9 languageName: node linkType: hard -"@aws-sdk/middleware-flexible-checksums@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.535.0" +"@aws-sdk/middleware-flexible-checksums@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.598.0" dependencies: - "@aws-crypto/crc32": 3.0.0 - "@aws-crypto/crc32c": 3.0.0 - "@aws-sdk/types": 3.535.0 - "@smithy/is-array-buffer": ^2.2.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-crypto/crc32": 5.2.0 + "@aws-crypto/crc32c": 5.2.0 + "@aws-sdk/types": 3.598.0 + "@smithy/is-array-buffer": ^3.0.0 + "@smithy/protocol-http": ^4.0.1 + "@smithy/types": ^3.1.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 14c04cd932bdb9029466079b248c1fa8222183de4c288bf12ad661cdc7717938485fdb973b7948da729e5be218573cfd2cbe74b51a1bc2bd27131ca7d67909c1 + checksum: 1311849976b0631055d2d79f991647a87cae742bba23a94f01d18164612ba303ff3bed629744ba58c04bfde371b69ad4eb29e266a7b022ea8529b9a7f6a18415 languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.535.0" +"@aws-sdk/middleware-host-header@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/protocol-http": ^4.0.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 13a22a5b19912a86fe872c9c0f6ba9ab758ba9483ce9a2e73fa68acae498b68404e38e7fc1e3962639a6c3f80ebe19ea5c5340e1024e11ab417998696c8a5dca + checksum: c505de5bf4f39051a55011b9b2da0b673bda668def00a9b3b4696a3146bfbf0e5509d3bde28ef238648158b863816ce85fbf5829228bb97450c826b7d24d40d0 languageName: node linkType: hard -"@aws-sdk/middleware-location-constraint@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-location-constraint@npm:3.535.0" +"@aws-sdk/middleware-location-constraint@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-location-constraint@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 4e89b6c5d4253568e599f0e8be37e80cf12a755ba89b89d9c9ae2ced75213850c41922fa1871a9c92345057e15d5db956a353841eb63353d8f2bb69a61d4a10d + checksum: ab1ae3ad3dc7fad76688c039136d602abe25ebd6b98b6fb61a86f02dbec4414a74334169d12581aae720fe9d372549e9b9dfb56ee87388602264b697db09ff9f languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-logger@npm:3.535.0" +"@aws-sdk/middleware-logger@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-logger@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: e264d05aa88fadd94d17000b1df79bf1931c5fbc2c871616de9b836bab7254d8c21e0fc2ac509a07af578bd823b795efafaf48daca805bc4493986288ed0c4ab + checksum: 8c90bf68b65fe82ae08bf0c665bfea335fef757f8be7ddac6f9059f9f149c9bebc68e034bc225d131d168a61d61a409936d4f4d260c4b2aa2251385238df765a languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.535.0" +"@aws-sdk/middleware-recursion-detection@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/protocol-http": ^4.0.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: b6b518243a10dcdcea7c1fd4790cf2e1e0e3d4363ebce51ac364c9b15631a6f3d1db44d00e7c75cbdf1d558a0d868583d6e1853e571e15e23d0d2901f168e2e4 + checksum: 161247dbbc8aa31d77c8d4c9c55264c775b5f9996e58451574605435c4a0ff6b9fce28be6f133ddce9f93a24f08c7af6fde59ef93ecb2cc4cd170a4db72b4833 languageName: node linkType: hard -"@aws-sdk/middleware-sdk-s3@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/middleware-sdk-s3@npm:3.556.0" +"@aws-sdk/middleware-sdk-s3@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-sdk-s3@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-arn-parser": 3.535.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/signature-v4": ^2.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/util-config-provider": ^2.3.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-arn-parser": 3.568.0 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/signature-v4": ^3.1.0 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/util-config-provider": ^3.0.0 tslib: ^2.6.2 - checksum: a50d96f898a8e6f7cfa0bc61c888240e1fd7aa55cb9fd9376d720f43d30a83d7ad4bd9d828224c125f62b362d77ccfc7fbd64c5c4563f97790f9683ea87abe93 + checksum: 2953ae0f2729ffc4ca68e51e8f3247d447004e5d3d787b333351f2972cc94b49f8379f3403d153c3c5940bda47e1930b0386b77c448ca81bc54bf40f7cb4111f languageName: node linkType: hard -"@aws-sdk/middleware-sdk-sqs@npm:3.552.0": - version: 3.552.0 - resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.552.0" +"@aws-sdk/middleware-sdk-sqs@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/util-hex-encoding": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@aws-sdk/types": 3.598.0 + "@smithy/smithy-client": ^3.1.2 + "@smithy/types": ^3.1.0 + "@smithy/util-hex-encoding": ^3.0.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: a2dfeab25b89b8c0f3204195df58bf5deefb261883db936c6701e70d5a1f6e2a0e8e3a756fea6a4f0e3a1dc4023d820c6b8b3717f759622ffa7cd8851cd9ed59 + checksum: 5b31bc50ffb2973a1a5108ca0a9a2fbf3cc96a403fd06e58994eb9e98e5804cb8fd2d2db977214d92ce30a5a256b54df156b285f7a89e286e7d0ceb3d9f69414 languageName: node linkType: hard @@ -1343,42 +1341,42 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-signing@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/middleware-signing@npm:3.556.0" +"@aws-sdk/middleware-signing@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-signing@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/signature-v4": ^2.3.0 - "@smithy/types": ^2.12.0 - "@smithy/util-middleware": ^2.2.0 + "@aws-sdk/types": 3.598.0 + "@smithy/property-provider": ^3.1.1 + "@smithy/protocol-http": ^4.0.1 + "@smithy/signature-v4": ^3.1.0 + "@smithy/types": ^3.1.0 + "@smithy/util-middleware": ^3.0.1 tslib: ^2.6.2 - checksum: b72c0223cc531d9eaac41124c3dcf60d974dbe0a5698fa6cf2ec877d73d83ff02ae310636478054ba5f7d1c3240ff277831c5144955ddb59e513b3de7cb4f272 + checksum: c952da22635dbca7b91c47e43df43a9f4826bbebc36e5851ce325e07f43451de015232145df32eed3190b23d3b051469bf4c381b94ab4eb367ca8f22de4a4670 languageName: node linkType: hard -"@aws-sdk/middleware-ssec@npm:3.537.0": - version: 3.537.0 - resolution: "@aws-sdk/middleware-ssec@npm:3.537.0" +"@aws-sdk/middleware-ssec@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-ssec@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 7a963134cab4c9056d249113f6d5e2847be28847fc8c39b943c487ff5d22b9b1d91092e801694e2da95929a4820c45f6b5afc22c655a6dcfb5eb82e44952de14 + checksum: 600afb96254d1085c402fec6c5b7f260ca64126104c4cf3ff6da9811c5cdf0dab5f34fadf68e449ec61f89a165479e1cfab8cd3135c720a2e7a678be4572c215 languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.540.0": - version: 3.540.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.540.0" +"@aws-sdk/middleware-user-agent@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@aws-sdk/util-endpoints": 3.598.0 + "@smithy/protocol-http": ^4.0.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 7ee609fb2b669f93657a87c291dff17f8315973ddbbeee36c54a0233b4911091916880f6e27da93fef01e5fd53654b3834a68cf74256b88b1c4dbe5880a4c14f + checksum: 11dcf64badadf8c6b3283b3cec4cb684467eaf57206782c68a9b758e6f7a4f1b632d5ed89bb6ffbc855bf6d3fb855f0a56858bda640a67c0812ced08cd19959f languageName: node linkType: hard @@ -1426,31 +1424,31 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.535.0" +"@aws-sdk/region-config-resolver@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/types": ^2.12.0 - "@smithy/util-config-provider": ^2.3.0 - "@smithy/util-middleware": ^2.2.0 + "@aws-sdk/types": 3.598.0 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/types": ^3.1.0 + "@smithy/util-config-provider": ^3.0.0 + "@smithy/util-middleware": ^3.0.1 tslib: ^2.6.2 - checksum: 7b556e47c721c0829ae635203a1dbcab7040e2885d2bdc37898eb3139dabb5f6da580b860202e3b7737330bfc02de5084a98ff8f8b5c36adcfe8e076b82d3487 + checksum: 649115771cb6b77e793088f3ee6eec346c1379f9f5d0e925f71103ad55c5f4a1132fca7e859a6b75ff46ecd1cc165a4eb260227596e4a2871118e6918602a726 languageName: node linkType: hard -"@aws-sdk/signature-v4-multi-region@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/signature-v4-multi-region@npm:3.556.0" +"@aws-sdk/signature-v4-multi-region@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/signature-v4-multi-region@npm:3.598.0" dependencies: - "@aws-sdk/middleware-sdk-s3": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/signature-v4": ^2.3.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/middleware-sdk-s3": 3.598.0 + "@aws-sdk/types": 3.598.0 + "@smithy/protocol-http": ^4.0.1 + "@smithy/signature-v4": ^3.1.0 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 0a23fbb8f99e1b8ab6c7523d5584864749a2ad5b244b78667d88d4a0eb0f74127e22fff4b44a9b694c235e70a66520ee72e0e57b129847d9405c6d907abf5e81 + checksum: 6e0aa7adfe98c452eaa269ea9dc68d2b914a3c5bdc00b5923c0a9003e54899b7d3b9ce14d305b5229200e658a18fdebb93977437f029e9a576c9fe9a3cded0b1 languageName: node linkType: hard @@ -1470,17 +1468,18 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/token-providers@npm:3.556.0" +"@aws-sdk/token-providers@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/token-providers@npm:3.598.0" dependencies: - "@aws-sdk/client-sso-oidc": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/shared-ini-file-loader": ^2.4.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/property-provider": ^3.1.1 + "@smithy/shared-ini-file-loader": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 15726af45c8a52837eb3291391c23e5b66a153218275c4fcc228a80f63169b401270ff736271401b6d4c301944bc20620d63dfb14a87bbe743a50e3157e68c7e + peerDependencies: + "@aws-sdk/client-sso-oidc": ^3.598.0 + checksum: 24197672226e1e953fa57ca10c6adae9c3f6b571fbf40f517609e028d8ea6ab45c3afd285bd999bc35c0690b3427be04d4af3f677ced6778b0a716e0dd4e5280 languageName: node linkType: hard @@ -1494,13 +1493,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/types@npm:3.535.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.347.0": - version: 3.535.0 - resolution: "@aws-sdk/types@npm:3.535.0" +"@aws-sdk/types@npm:3.598.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.347.0": + version: 3.598.0 + resolution: "@aws-sdk/types@npm:3.598.0" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 3f735c78ea3a6f37d05387286f6d18b0e5deb41442095bd2f7c27b000659962872d1c801fa8484a6ac4b7d2725b2e176dc628c3fa2a903a3141d4be76488d48f + checksum: 9b2bd50d6935422dd1046e6eaa48c4c774d06aa1374bf4600a3af2c7a52432b5e25ec111cf49976b07b03d7cb5f4fa6fd44b7ce8a67dd0b3a4cee4abaf9e6fa5 languageName: node linkType: hard @@ -1515,12 +1514,12 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-arn-parser@npm:3.535.0, @aws-sdk/util-arn-parser@npm:^3.310.0": - version: 3.535.0 - resolution: "@aws-sdk/util-arn-parser@npm:3.535.0" +"@aws-sdk/util-arn-parser@npm:3.568.0, @aws-sdk/util-arn-parser@npm:^3.310.0": + version: 3.568.0 + resolution: "@aws-sdk/util-arn-parser@npm:3.568.0" dependencies: tslib: ^2.6.2 - checksum: 0e4c4ea080c7c6da00d359c337a1f9d961eac20c35cebad9cb6bb9b618f981955643990de7bfd6b53c29367a6d33550fe27b2a7539efdff08e01bdd303f0c5c2 + checksum: e3c45e5d524a772954d0a33614d397414185b9eb635423d01253cad1c1b9add625798ed9cf23343d156fae89c701f484bc062ab673f67e2e2edfe362fde6d170 languageName: node linkType: hard @@ -1534,15 +1533,15 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.540.0": - version: 3.540.0 - resolution: "@aws-sdk/util-endpoints@npm:3.540.0" +"@aws-sdk/util-endpoints@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/util-endpoints@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/types": ^2.12.0 - "@smithy/util-endpoints": ^1.2.0 + "@aws-sdk/types": 3.598.0 + "@smithy/types": ^3.1.0 + "@smithy/util-endpoints": ^2.0.2 tslib: ^2.6.2 - checksum: 62312773965480f8df5edb62ecf82ab3e54d5aa1b1f7eebdad78a2925eab47218b0268bc25a5d03598ac4d0c08935733031a2e3e1ce72531535ed1ea8a9b56c3 + checksum: 6fb92e8c99b6ce96cda21c9d1744a290c683bae8d82394c1b1fe7ed7d3cb0a18d4025b8863532680db3f550ad130e54d528c64a0a32f398f3c00c5ce2e043ecd languageName: node linkType: hard @@ -1594,32 +1593,32 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-browser@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.535.0" +"@aws-sdk/util-user-agent-browser@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/types": ^3.1.0 bowser: ^2.11.0 tslib: ^2.6.2 - checksum: 148b82900e4b9efd24f5fc4152a8d6010c90eb019517fa3c00c3ac42205055f7611ef3834fb63397def40e600ea20f901177a7dd5b6aefa2aef4208e994f7d90 + checksum: c53afc0fe7a07838ad22ae1e9ed6834d56a69cb0ad623d4912deeaa715af479b64266965fce30e7210e576118f80ceb525f79f504dc459fe0294fd15e694752e languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.535.0" +"@aws-sdk/util-user-agent-node@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.598.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/types": ^2.12.0 + "@aws-sdk/types": 3.598.0 + "@smithy/node-config-provider": ^3.1.1 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 peerDependencies: aws-crt: ">=1.0.0" peerDependenciesMeta: aws-crt: optional: true - checksum: f214c406fccde14591d1df25fed662e573510cdf1d5829d22e7a93e517ea4a3905acd123eaaeafdb8b217400e8c8e159231d37be02b67307922023996b398f42 + checksum: 1560fabf19b236cfbce42769e1ef7e46bdad881b8a4b0ce069401d9a6edd5e1b195f45cb2847abf9ef1453d2e69447e7a3dabc92b037d9a41fe58960538db1ae languageName: node linkType: hard @@ -1642,13 +1641,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/xml-builder@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/xml-builder@npm:3.535.0" +"@aws-sdk/xml-builder@npm:3.598.0": + version: 3.598.0 + resolution: "@aws-sdk/xml-builder@npm:3.598.0" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.1.0 tslib: ^2.6.2 - checksum: 9320f6600c7852b681ed4171f1521eda166321ef7ffea5a6b99a1d328835bb12f7423431ea23a696c678ec4fc8e6dbb2f979d941289f6e0cb55c3da7d5eee140 + checksum: 6b9fa385f749219d0a0654445e5deba54c7753d3e0da795dfc2bfdbaeb59fbfc8ef0e3f477c6aff6181a12a11ac87e3f84dedbbd1d1adb2c32941b149401abcf languageName: node linkType: hard @@ -15002,177 +15001,187 @@ __metadata: languageName: node linkType: hard -"@smithy/chunked-blob-reader-native@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/chunked-blob-reader-native@npm:2.2.0" +"@smithy/abort-controller@npm:^3.0.1, @smithy/abort-controller@npm:^3.1.0": + version: 3.1.0 + resolution: "@smithy/abort-controller@npm:3.1.0" dependencies: - "@smithy/util-base64": ^2.3.0 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: ac619f18844e8a8288672c40b8967a82b78f5398119638b3e4fcadf451a3356139307c2d9f24c8c041530238f1ce6e0f90ce82adfcb050d08afefa2f0541c2d0 + checksum: 78643bddda2bcb68e00bb95ae866741407236b92b1834796c0855710950386ae1e5e67d72fb42ec444e8a4dc4357a1527c4f331324a2fad156468f5a0cccf128 languageName: node linkType: hard -"@smithy/chunked-blob-reader@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/chunked-blob-reader@npm:2.2.0" +"@smithy/chunked-blob-reader-native@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/chunked-blob-reader-native@npm:3.0.0" dependencies: + "@smithy/util-base64": ^3.0.0 tslib: ^2.6.2 - checksum: f5acb1e812f97d7c233ccf955557ac10c7e94c8c9610d2fad715d1010fe30ee686a93a5d6e589ce8ae4eb7cf201d5eab61cee5e8646bbebdfa8a5f23693d7a5a + checksum: f97c0c0ce5e9bd2350883df3c232311aa82eb87eb387125f685900326f86fc3aca208e9004291f742f6978abf91a0c1112cc9a803cd0caf0dffbcfa9b6d0239e languageName: node linkType: hard -"@smithy/config-resolver@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/config-resolver@npm:2.2.0" +"@smithy/chunked-blob-reader@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/chunked-blob-reader@npm:3.0.0" dependencies: - "@smithy/node-config-provider": ^2.3.0 - "@smithy/types": ^2.12.0 - "@smithy/util-config-provider": ^2.3.0 - "@smithy/util-middleware": ^2.2.0 tslib: ^2.6.2 - checksum: dcb15d40faf46c370cd83dfbf1e632fae29c64c500b33b53850a520cfb02c9fa6f7e239c07824793b47645462567d51cb1554c02f9ec4531bd51bc759aede2ed + checksum: 6f520884ade14f1073adb640db2f03eb22a9920f342f37958df3e98327890b741cd909b16cbbc6f70c6c8dd250d6b3a8d76841b685d4871b0403f309267def4f languageName: node linkType: hard -"@smithy/core@npm:^1.4.2": - version: 1.4.2 - resolution: "@smithy/core@npm:1.4.2" +"@smithy/config-resolver@npm:^3.0.2, @smithy/config-resolver@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/config-resolver@npm:3.0.3" dependencies: - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-retry": ^2.3.1 - "@smithy/middleware-serde": ^2.3.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/util-middleware": ^2.2.0 + "@smithy/node-config-provider": ^3.1.2 + "@smithy/types": ^3.2.0 + "@smithy/util-config-provider": ^3.0.0 + "@smithy/util-middleware": ^3.0.2 tslib: ^2.6.2 - checksum: 414ec1c392ab5346f2b833f310078d7e850df8b9e5db6fedbce65116146c2fda116d56db841401ba05b5e7399a5f5c426870d324bf6fd060143ce66e2f3eafbb + checksum: 7a7baf23e64ed85d4229bfd320a3ea96087c57ce1b94638a89bab5f92dcc24ec22c11740d90f2fab38eb39eeb860463ae98b24598555c2b55a01bd79c20ef99b languageName: node linkType: hard -"@smithy/credential-provider-imds@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/credential-provider-imds@npm:2.3.0" +"@smithy/core@npm:^2.2.1": + version: 2.2.3 + resolution: "@smithy/core@npm:2.2.3" dependencies: - "@smithy/node-config-provider": ^2.3.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 + "@smithy/middleware-endpoint": ^3.0.3 + "@smithy/middleware-retry": ^3.0.6 + "@smithy/middleware-serde": ^3.0.2 + "@smithy/protocol-http": ^4.0.2 + "@smithy/smithy-client": ^3.1.4 + "@smithy/types": ^3.2.0 + "@smithy/util-middleware": ^3.0.2 tslib: ^2.6.2 - checksum: dd57e09e60bd51ed103f7a5363a43e1373470ea3cee04ace66f5bbaafab005355ffbfa3e137e2ecac34aa28911fb5b6ecac60845846c6a4a5432f3e57a74b837 + checksum: 6addaede7f4699c48d690872647bbc86efc5bf9adb088557cfd4263e629e6bd7d45a1de983824a7c5ff608ec2cd42d7c6f61854d3d33b8ded352df550789b34b languageName: node linkType: hard -"@smithy/eventstream-codec@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/eventstream-codec@npm:2.2.0" +"@smithy/credential-provider-imds@npm:^3.1.1, @smithy/credential-provider-imds@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/credential-provider-imds@npm:3.1.2" dependencies: - "@aws-crypto/crc32": 3.0.0 - "@smithy/types": ^2.12.0 - "@smithy/util-hex-encoding": ^2.2.0 + "@smithy/node-config-provider": ^3.1.2 + "@smithy/property-provider": ^3.1.2 + "@smithy/types": ^3.2.0 + "@smithy/url-parser": ^3.0.2 tslib: ^2.6.2 - checksum: ae59067964e19c6728b1be74a6e19793e4d3decdcbcea546bd40f77c3cc1eacc48c30272ef68927ba477c2b6450d023474f2dec516dfd93e204150ba18cab697 + checksum: bf0ce9f7c510f5f7e05d08c2b1d861f133016457e3872bfc5e4ac9b22f26123adcf773a562189971e2ce97bdad2f576a4eefb764808df2ae1833e77be86358f2 languageName: node linkType: hard -"@smithy/eventstream-serde-browser@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/eventstream-serde-browser@npm:2.2.0" +"@smithy/eventstream-codec@npm:^3.1.1": + version: 3.1.1 + resolution: "@smithy/eventstream-codec@npm:3.1.1" dependencies: - "@smithy/eventstream-serde-universal": ^2.2.0 - "@smithy/types": ^2.12.0 + "@aws-crypto/crc32": 5.2.0 + "@smithy/types": ^3.2.0 + "@smithy/util-hex-encoding": ^3.0.0 tslib: ^2.6.2 - checksum: c00bd592365f42ddafcad83f06d3c85ce8ee21bd806de903043ef132de9acca8bf1592ed811b11daba1742332928fc73a66c9032b06df2f6526da0339918f8d5 + checksum: fdc7a2bcf99f7c830ba24b5745877ec26556613423a025c6b122b167ef92a76a860f7dffe21f25667f12c2736a121f4e2064050dcf768406a60ce3ebc029e402 languageName: node linkType: hard -"@smithy/eventstream-serde-config-resolver@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/eventstream-serde-config-resolver@npm:2.2.0" +"@smithy/eventstream-serde-browser@npm:^3.0.2": + version: 3.0.3 + resolution: "@smithy/eventstream-serde-browser@npm:3.0.3" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/eventstream-serde-universal": ^3.0.3 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: a35dbcbc14ad1825ce22a9e7daac93067d8ade6173a3ce33b819eed61390f8d93ea63b70945f6d1bced175fad58def3d09a14ee3043c63a798ecef407b2d1701 + checksum: 3e41fb32f06dc266ab41185482e441068c1e84ac5637462fc107511a495a7338972f10568bb57970e22eef2d14e024f93e0991b30b54545bca5b5189add5d41e languageName: node linkType: hard -"@smithy/eventstream-serde-node@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/eventstream-serde-node@npm:2.2.0" +"@smithy/eventstream-serde-config-resolver@npm:^3.0.1": + version: 3.0.2 + resolution: "@smithy/eventstream-serde-config-resolver@npm:3.0.2" dependencies: - "@smithy/eventstream-serde-universal": ^2.2.0 - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 1d4971b99654c4672716608a63e668ccefd78cc1806c0ea4df5c3cc0ca0208b7647f7914d2c77a37d0a29b31b66cff660ce2ab2f46f56d997c9a58ea6b6241b2 + checksum: 5c2113b6acc65df61f6fc844054c5a85825305e1d9f47987a5f350b603e304c8d90ad2c62cb7a098f10b7243c4f466fa413264821d261a3b69dc12c33fa976d4 languageName: node linkType: hard -"@smithy/eventstream-serde-universal@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/eventstream-serde-universal@npm:2.2.0" +"@smithy/eventstream-serde-node@npm:^3.0.2": + version: 3.0.3 + resolution: "@smithy/eventstream-serde-node@npm:3.0.3" dependencies: - "@smithy/eventstream-codec": ^2.2.0 - "@smithy/types": ^2.12.0 + "@smithy/eventstream-serde-universal": ^3.0.3 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: c28038c2f57deed7b5e0e5f8ab8150d4a7947f2971241da96ef1d53b45d83dfa661717065f059099c420ee66ae2455818ae124bb8601b609558040d4a7509227 + checksum: 29e2323b92a87302518ecfd75096e856c77a3d39ffa2680ff56e11c2c01b4434f56f86940e13c636e207af7cadf867f824f5c60249c53e1c27faa1cf932b6eb9 languageName: node linkType: hard -"@smithy/fetch-http-handler@npm:^2.5.0": - version: 2.5.0 - resolution: "@smithy/fetch-http-handler@npm:2.5.0" +"@smithy/eventstream-serde-universal@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/eventstream-serde-universal@npm:3.0.3" dependencies: - "@smithy/protocol-http": ^3.3.0 - "@smithy/querystring-builder": ^2.2.0 - "@smithy/types": ^2.12.0 - "@smithy/util-base64": ^2.3.0 + "@smithy/eventstream-codec": ^3.1.1 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 91a58ac32c6b4afc6d7fb2b9ac3e3b817171f76e09b013a6506308b044455054444a92e1acbd8f98bdd159b15fdd44b1e3fb52c21cbb2e69be8e3698d2206021 + checksum: 6c0c3602e3e79bb0abe47f1d7b8c277f58879ab613cda99d80cf0e825653055f892daee313e6d40e5096932e004838e3c9f674e440b97921520257f80337bed8 languageName: node linkType: hard -"@smithy/hash-blob-browser@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/hash-blob-browser@npm:2.2.0" +"@smithy/fetch-http-handler@npm:^3.0.2, @smithy/fetch-http-handler@npm:^3.1.0": + version: 3.1.0 + resolution: "@smithy/fetch-http-handler@npm:3.1.0" dependencies: - "@smithy/chunked-blob-reader": ^2.2.0 - "@smithy/chunked-blob-reader-native": ^2.2.0 - "@smithy/types": ^2.12.0 + "@smithy/protocol-http": ^4.0.2 + "@smithy/querystring-builder": ^3.0.2 + "@smithy/types": ^3.2.0 + "@smithy/util-base64": ^3.0.0 tslib: ^2.6.2 - checksum: 1b748b4449ccee723c8b47a412491283fa7b5a2a6c27b0b73e03d905c2af70b56b74d63a658d8ef0bd330cc4617bc11431c86e24a4932b4722aad08e1b25e576 + checksum: 7b9b928e8a094e41a9c7516aa2fcfd3bb88b0271737e1d4fa301973a49f577094fa967ba481a0cf6e5c977be6bb8b2898d868b3269a476cae2aaaed582277733 languageName: node linkType: hard -"@smithy/hash-node@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/hash-node@npm:2.2.0" +"@smithy/hash-blob-browser@npm:^3.1.0": + version: 3.1.1 + resolution: "@smithy/hash-blob-browser@npm:3.1.1" dependencies: - "@smithy/types": ^2.12.0 - "@smithy/util-buffer-from": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@smithy/chunked-blob-reader": ^3.0.0 + "@smithy/chunked-blob-reader-native": ^3.0.0 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 3305b5778fa99558375b16629ad98fd00a1fb33ea905037977b0a7c93d92c8de1481756ef7dbc004e45210b23f983dec04bcd13d43c98f36a5f47291cbed9d89 + checksum: 9a54f0b7d48d5a411c2e3361f8a946d71b75d54965bc3d2a0524d0fe01fc032c2ee2a4e105104daefa14e3e02f0e38b9e83faf0b40d3933a33b87d8b8b142c8f languageName: node linkType: hard -"@smithy/hash-stream-node@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/hash-stream-node@npm:2.2.0" +"@smithy/hash-node@npm:^3.0.1": + version: 3.0.2 + resolution: "@smithy/hash-node@npm:3.0.2" dependencies: - "@smithy/types": ^2.12.0 - "@smithy/util-utf8": ^2.3.0 + "@smithy/types": ^3.2.0 + "@smithy/util-buffer-from": ^3.0.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 191d76fd1df705c32d24463794f8b8b391061c7ca7265591cd4f070259fa80395c2f115fd3d37f6bb3a4a2303b3811a31509ea767d0c3d0a9644789ae8283118 + checksum: 2b7b678d429b9806a28f18472f8beec45f5a2e1d004b084cc4b591c1239565c46435b278c7f76be09790d6d6eabc617e7d0f3aef11c375721b78600506d62856 languageName: node linkType: hard -"@smithy/invalid-dependency@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/invalid-dependency@npm:2.2.0" +"@smithy/hash-stream-node@npm:^3.1.0": + version: 3.1.1 + resolution: "@smithy/hash-stream-node@npm:3.1.1" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.2.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: ed17980ccdf4c564cfcb517f3959dfeb7c7dbddd76eaf2c9e10031ebd19e78e56609df3377626215e51a6c4b98db03cfa88ad46f15ba26bb55c34351f3182a98 + checksum: 21d4d8ffca488a1aa83d97eb418197ca4b9c25329ce2d67a5978cd4b74ee7e609ebcb510fce3a271ce240b5e421073cda516e23cde7d9fedbb682ee02d7b7c9f + languageName: node + linkType: hard + +"@smithy/invalid-dependency@npm:^3.0.1": + version: 3.0.2 + resolution: "@smithy/invalid-dependency@npm:3.0.2" + dependencies: + "@smithy/types": ^3.2.0 + tslib: ^2.6.2 + checksum: 21f0f2669989d9b8ffdc86e80fa8d0a39b5ada187a21c61bc4405936a31fa054a59577fa8fde4de707de559cc3e08c80aaac0205aaacf0eaf3a2ff620fa12830 languageName: node linkType: hard @@ -15185,93 +15194,102 @@ __metadata: languageName: node linkType: hard -"@smithy/md5-js@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/md5-js@npm:2.2.0" +"@smithy/is-array-buffer@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/is-array-buffer@npm:3.0.0" dependencies: - "@smithy/types": ^2.12.0 - "@smithy/util-utf8": ^2.3.0 tslib: ^2.6.2 - checksum: ae343c198a8d8c6689bcb1d7f766e29578d370e8d79180db9b6183b5c74ac091829e8abe3053df0589f53324c01a79c7f9e889e5cd92094e3b5c4be96fb7b970 + checksum: ce7440fcb1ce3c46722cff11c33e2f62a9df86d74fa2054a8e6b540302a91211cf6e4e3b1b7aac7030c6c8909158c1b6867c394201fa8afc6b631979956610e5 languageName: node linkType: hard -"@smithy/middleware-content-length@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/middleware-content-length@npm:2.2.0" +"@smithy/md5-js@npm:^3.0.1": + version: 3.0.2 + resolution: "@smithy/md5-js@npm:3.0.2" dependencies: - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.2.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 1eae8d2b6f432ce9a849e741d4f2426baee8a51f22a5262c11802e125078ee33d9d8f4183fb142043ba9d1371adad9c835c784333a394d865fb248339f7482e6 + checksum: cc8857d043b53234ce280776ac7592ed6287c911d7ac45d3b9836adbf01b9e814a1f164b8a8c5b654bde14e8ce4baed17494b983d4cfee61584da623f9b794e5 languageName: node linkType: hard -"@smithy/middleware-endpoint@npm:^2.5.1": - version: 2.5.1 - resolution: "@smithy/middleware-endpoint@npm:2.5.1" +"@smithy/middleware-content-length@npm:^3.0.1": + version: 3.0.2 + resolution: "@smithy/middleware-content-length@npm:3.0.2" dependencies: - "@smithy/middleware-serde": ^2.3.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/shared-ini-file-loader": ^2.4.0 - "@smithy/types": ^2.12.0 - "@smithy/url-parser": ^2.2.0 - "@smithy/util-middleware": ^2.2.0 + "@smithy/protocol-http": ^4.0.2 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 7ac2a35a6f52c33d868fc4b73330ae34fecfc43c59b8d501ee9fb81924c6747494700b55b3025b83fe7bea3d4e323c8853ec5b117c17cccf06cc27bbc4f492b2 + checksum: 67758207c3a26eb6d44fd922d178299418fc42a07937813364a17a76547bf736df75d279cb493fca9ac5c3897c0c8d24c6e124f3edc143c991a26b44521eb423 languageName: node linkType: hard -"@smithy/middleware-retry@npm:^2.3.1": - version: 2.3.1 - resolution: "@smithy/middleware-retry@npm:2.3.1" +"@smithy/middleware-endpoint@npm:^3.0.2, @smithy/middleware-endpoint@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/middleware-endpoint@npm:3.0.3" dependencies: - "@smithy/node-config-provider": ^2.3.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/service-error-classification": ^2.1.5 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-retry": ^2.2.0 + "@smithy/middleware-serde": ^3.0.2 + "@smithy/node-config-provider": ^3.1.2 + "@smithy/shared-ini-file-loader": ^3.1.2 + "@smithy/types": ^3.2.0 + "@smithy/url-parser": ^3.0.2 + "@smithy/util-middleware": ^3.0.2 + tslib: ^2.6.2 + checksum: 15a37293aa590bd0c8ab59430e967f786500603bca92dbde655480c3b7c1812a8cbcd267ff31691c2d8ea596f7917769ef91fa4033e07ec9971bf252fc12ebcd + languageName: node + linkType: hard + +"@smithy/middleware-retry@npm:^3.0.4, @smithy/middleware-retry@npm:^3.0.6": + version: 3.0.6 + resolution: "@smithy/middleware-retry@npm:3.0.6" + dependencies: + "@smithy/node-config-provider": ^3.1.2 + "@smithy/protocol-http": ^4.0.2 + "@smithy/service-error-classification": ^3.0.2 + "@smithy/smithy-client": ^3.1.4 + "@smithy/types": ^3.2.0 + "@smithy/util-middleware": ^3.0.2 + "@smithy/util-retry": ^3.0.2 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: 5eebf9d26fccc6c8c517924463e93d244edebe52d120b28d5d705904f83773da1734296b8d57b4f30a15cbf36690e508f5946dfd56749cbcda501d08cb778933 + checksum: c17ac5665e0dd2315e996c219b5aa2327c9270a49ca7dc64b8d81c80261f9d0098d3725641f2e4c87aac293c283d709fb062b5c7be6912e72f9042492a3e91d9 languageName: node linkType: hard -"@smithy/middleware-serde@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/middleware-serde@npm:2.3.0" +"@smithy/middleware-serde@npm:^3.0.1, @smithy/middleware-serde@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/middleware-serde@npm:3.0.2" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 5393370c0f8a820d8ca36eccecff5b6434c4f81fbaad8800088fb4c8dad5312bf3eb47f67533784de959807bbb3379c23d81a1bcbaf8824254034dd2b83fd76b + checksum: 16c933ecb8061ff9fcf49ecabcc54b6d56de0e02464e5dd995ac729ad06e70be7a341c329b0b7cc1b33c8dbaa31372e337130e9eb6aac4c2df63ce37cb36d54f languageName: node linkType: hard -"@smithy/middleware-stack@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/middleware-stack@npm:2.2.0" +"@smithy/middleware-stack@npm:^3.0.1, @smithy/middleware-stack@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/middleware-stack@npm:3.0.2" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 293d76764e327a5ada4ea7de268f451e62a6a56983ba7dcdbc63fdbb0427c01071a9a81d7807b16586977df829ce5d9587facbd9367b089841bbc9fc329ce6af + checksum: 70ec59d020ae6d8c53aefecb039fb511cfa67a57ce00ba1e41d2c3da346265cc18bdf1e0724b0df10f1ef838807e151e93f6da6e886fafbac51d2ed962b795d1 languageName: node linkType: hard -"@smithy/node-config-provider@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/node-config-provider@npm:2.3.0" +"@smithy/node-config-provider@npm:^3.1.1, @smithy/node-config-provider@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/node-config-provider@npm:3.1.2" dependencies: - "@smithy/property-provider": ^2.2.0 - "@smithy/shared-ini-file-loader": ^2.4.0 - "@smithy/types": ^2.12.0 + "@smithy/property-provider": ^3.1.2 + "@smithy/shared-ini-file-loader": ^3.1.2 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 9c1dc6d97e0379d947498e7d64e593ea183d5f2c89dace4561c1c613850bf264581b597105c15d64ceabdea954e57ad8e6bf9e42642ddc3f737464f350ffbb5b + checksum: 596e7a6b92fa68f6c172969bde6a04aadf35634f78a601351642b44bc271f3ad5444588a8c3dea8f7cdbe65a2d69e1c1d93291bf8d240736a035ac8db4e96ce3 languageName: node linkType: hard -"@smithy/node-http-handler@npm:^2.1.7, @smithy/node-http-handler@npm:^2.5.0": +"@smithy/node-http-handler@npm:^2.1.7": version: 2.5.0 resolution: "@smithy/node-http-handler@npm:2.5.0" dependencies: @@ -15284,13 +15302,26 @@ __metadata: languageName: node linkType: hard -"@smithy/property-provider@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/property-provider@npm:2.2.0" +"@smithy/node-http-handler@npm:^3.0.1, @smithy/node-http-handler@npm:^3.1.0": + version: 3.1.0 + resolution: "@smithy/node-http-handler@npm:3.1.0" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/abort-controller": ^3.1.0 + "@smithy/protocol-http": ^4.0.2 + "@smithy/querystring-builder": ^3.0.2 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 8d257cbc5222baf6706e288c3b51196588f135878141f8af76fcb3f0abafc027ed46cf4bb938266d1906111175082ee85f73806d5a2b1c929aee16ec8b5283e6 + checksum: 915cc2876cfe5b2330e868aa512930d4c126192d7695354dc2a88aab1c6639968ace36c1e8778c8a647a8b6f3f3faac2a14870607043cba972e05ee94491738a + languageName: node + linkType: hard + +"@smithy/property-provider@npm:^3.1.1, @smithy/property-provider@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/property-provider@npm:3.1.2" + dependencies: + "@smithy/types": ^3.2.0 + tslib: ^2.6.2 + checksum: 9ec0cce2728dd4a0d327fef523ca5bddcba9a7750e6e5a614293d6ba4c12d6b86c32020689481a529b4797d07315fd84647f13ea0dbe91f1da7932c954b08421 languageName: node linkType: hard @@ -15304,6 +15335,16 @@ __metadata: languageName: node linkType: hard +"@smithy/protocol-http@npm:^4.0.1, @smithy/protocol-http@npm:^4.0.2": + version: 4.0.2 + resolution: "@smithy/protocol-http@npm:4.0.2" + dependencies: + "@smithy/types": ^3.2.0 + tslib: ^2.6.2 + checksum: e1b419e0324f20300c490491cbc32b9d151579a6ce11f708b76ed265ef3499d404d9c0e3443692984514a0f8042b456f5c7e1a62694d42c7dc9bc64bfcff0301 + languageName: node + linkType: hard + "@smithy/querystring-builder@npm:^2.2.0": version: 2.2.0 resolution: "@smithy/querystring-builder@npm:2.2.0" @@ -15315,61 +15356,72 @@ __metadata: languageName: node linkType: hard -"@smithy/querystring-parser@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/querystring-parser@npm:2.2.0" +"@smithy/querystring-builder@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/querystring-builder@npm:3.0.2" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.2.0 + "@smithy/util-uri-escape": ^3.0.0 tslib: ^2.6.2 - checksum: 9b27751c329fecc84bdfe7f128ab766c7e5f1d4bdda6184699a0df8999e95aef21fafc6179d6c693e519c78874e738fd9afb5ac4679901cb68d092a86a612419 + checksum: c6f6fc8681879daed9c85b3fd2d81cbbf553addbdc1d6ab2660687d967af40eba0112e40cf1157bdd4c42784bc22977a3da9ed9dde674b7ede5e70720a0b38af languageName: node linkType: hard -"@smithy/service-error-classification@npm:^2.1.5": - version: 2.1.5 - resolution: "@smithy/service-error-classification@npm:2.1.5" +"@smithy/querystring-parser@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/querystring-parser@npm:3.0.2" dependencies: - "@smithy/types": ^2.12.0 - checksum: 00ac54110a258c7a47c62d4f655d4998bd40e5adb47e10281b28df7a585f2f1e960dc35325eac006636280e7fb2b81dbeb32b89e08bac87acc136c4d29a4dc53 + "@smithy/types": ^3.2.0 + tslib: ^2.6.2 + checksum: 7f18281e8d73c70dc020e1a8719a8322d88130c24e8c8cffa39ffe83e9f18d28bb9d420e6026ddb17d60ac950b0fb5b9465a4ba8493086e6186f60a9573b2ad8 languageName: node linkType: hard -"@smithy/shared-ini-file-loader@npm:^2.4.0": - version: 2.4.0 - resolution: "@smithy/shared-ini-file-loader@npm:2.4.0" +"@smithy/service-error-classification@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/service-error-classification@npm:3.0.2" dependencies: - "@smithy/types": ^2.12.0 - tslib: ^2.6.2 - checksum: b0c9e045bfe2150e07f4b31ae7d69d3646679337df9fec1e1201b845cc64ea2250c37db8e8d0e7573fc3c11188164adba43bbaf32275fa8a9f70e8bbc77146bf + "@smithy/types": ^3.2.0 + checksum: f7cfd6438286942ec1f7f059c4bdac517c64833fcbea27198880106c7e55d0c2083f0c8e22c8fe5a68f0d86e5bd33a78f644898b48008b2f14c0c13d46f0923c languageName: node linkType: hard -"@smithy/signature-v4@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/signature-v4@npm:2.3.0" +"@smithy/shared-ini-file-loader@npm:^3.1.1, @smithy/shared-ini-file-loader@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/shared-ini-file-loader@npm:3.1.2" dependencies: - "@smithy/is-array-buffer": ^2.2.0 - "@smithy/types": ^2.12.0 - "@smithy/util-hex-encoding": ^2.2.0 - "@smithy/util-middleware": ^2.2.0 - "@smithy/util-uri-escape": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 96050956b86876d0137af9b003d0a30005766bffc730495d7c106bd2eb05c8ada2da23ceac51d56e04f98b304e0ea55d698e1a10c99cda3ade44b3ac30166a00 + checksum: bbb7ceaefdcbe4e43e5a65cf424e41f6a70e44fc9b05b7f8c968bd6134253e04af4455ad0fa91fda18f55695b7992c8bfc5281aa201be2a69f7733014fd84042 languageName: node linkType: hard -"@smithy/smithy-client@npm:^2.5.1": - version: 2.5.1 - resolution: "@smithy/smithy-client@npm:2.5.1" +"@smithy/signature-v4@npm:^3.1.0": + version: 3.1.1 + resolution: "@smithy/signature-v4@npm:3.1.1" dependencies: - "@smithy/middleware-endpoint": ^2.5.1 - "@smithy/middleware-stack": ^2.2.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/types": ^2.12.0 - "@smithy/util-stream": ^2.2.0 + "@smithy/is-array-buffer": ^3.0.0 + "@smithy/types": ^3.2.0 + "@smithy/util-hex-encoding": ^3.0.0 + "@smithy/util-middleware": ^3.0.2 + "@smithy/util-uri-escape": ^3.0.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 10d51793aab8f6e0ba0890a2a101216ffc3a1c43664f8ed9688dcbc174ca0f83f2d1c8d7af484c84491174067af3d6b235b765a58b12f2308a6bfe42b1d74f59 + checksum: f7eca9889ac4252e8fff76bf31a75bbc8afebc7ac690e3fddffadaccde64fd05305b6e22ad00f8d8da3bb3ca8739d310d6abe70350a4c12c996fb0335a8bd975 + languageName: node + linkType: hard + +"@smithy/smithy-client@npm:^3.1.2, @smithy/smithy-client@npm:^3.1.4": + version: 3.1.4 + resolution: "@smithy/smithy-client@npm:3.1.4" + dependencies: + "@smithy/middleware-endpoint": ^3.0.3 + "@smithy/middleware-stack": ^3.0.2 + "@smithy/protocol-http": ^4.0.2 + "@smithy/types": ^3.2.0 + "@smithy/util-stream": ^3.0.4 + tslib: ^2.6.2 + checksum: be1ce3523d5b49d1c2fb75695201dcc3748583050675efc7910b0a8bc9444c781daf435bec711166e6d2f0238ed301187283362c33aa31aefd2c21b09fb305a5 languageName: node linkType: hard @@ -15391,43 +15443,52 @@ __metadata: languageName: node linkType: hard -"@smithy/url-parser@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/url-parser@npm:2.2.0" +"@smithy/types@npm:^3.1.0, @smithy/types@npm:^3.2.0": + version: 3.2.0 + resolution: "@smithy/types@npm:3.2.0" dependencies: - "@smithy/querystring-parser": ^2.2.0 - "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: f21f1e44bc2a4634220465990651f5ee0708cb6759b3685b8a8c00cc2cd64bbbc7807f66cd79ec6e654f7245867d4fb4ced406ad5c14612ebc47eae3f34e63c5 + checksum: f07caa63cd2f1ed9a14612a9493fcc9c0aca974593e16c1328daecc7f36af2ece5e5e79c24212966180f88a183abf078bfbcd98cf362a8d8f95f3f8642d41389 languageName: node linkType: hard -"@smithy/util-base64@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/util-base64@npm:2.3.0" +"@smithy/url-parser@npm:^3.0.1, @smithy/url-parser@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/url-parser@npm:3.0.2" dependencies: - "@smithy/util-buffer-from": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@smithy/querystring-parser": ^3.0.2 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 2ce995c5d12037e9518bb2732f24090bc493d48118dfd6519faa41e19cd91863895bc0b5958b790d2cdeb919a8c410790dcffa3a452d560f0eeab73dc0c92cbd + checksum: a0dac1ff3eac440d3dba7f2ad80eb3cfb46cf912ceb4a533b0bd87ad5b5f1e9b641ca9a247844129c33dc2901cbe753c89185b70c6d323b781b83451a738702e languageName: node linkType: hard -"@smithy/util-body-length-browser@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/util-body-length-browser@npm:2.2.0" +"@smithy/util-base64@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-base64@npm:3.0.0" dependencies: + "@smithy/util-buffer-from": ^3.0.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: e9c1d16b3b95d529011476e6154eaf282d3a983204b29dcf1e7ef04a9f5c2deae30167e06190f315771c813c768f19f486d3139fe9fcaf34d12c2333350f3412 + checksum: 413f26046a7e98b2661a078f218a8d040c820fc5a02f5e364aff58c3957e28fde1ac4048c2ebbad5d87b9da4b9aa98a8d4a7fb0d2ce97def33738bd7d8d79aa0 languageName: node linkType: hard -"@smithy/util-body-length-node@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/util-body-length-node@npm:2.3.0" +"@smithy/util-body-length-browser@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-body-length-browser@npm:3.0.0" dependencies: tslib: ^2.6.2 - checksum: 5d5c31b071e0b3222dcfe863ea2d179253f0dfaa30d03f40ebfa352ed292e00a451053cc523e27527e61094d5ed475069d2287ef19a857c6da0364ca71cfdf3c + checksum: b01d8258b9a25b262734fc49cefefe48583ba193c3eefd49a6f7fd5922c3015d23dda88b52f3dd9a16827cad16b5b9425eef01e91bd0c71bb5abc469d2952c07 + languageName: node + linkType: hard + +"@smithy/util-body-length-node@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-body-length-node@npm:3.0.0" + dependencies: + tslib: ^2.6.2 + checksum: da1baf4790609d3dc28c88385c7274fdf9b91a641fe3c5af22b78e18156df17bd470181348f43b2c739680936b1dafb1526158dfd817c3d9ecb71e653b4cbe3f languageName: node linkType: hard @@ -15441,97 +15502,107 @@ __metadata: languageName: node linkType: hard -"@smithy/util-config-provider@npm:^2.3.0": - version: 2.3.0 - resolution: "@smithy/util-config-provider@npm:2.3.0" +"@smithy/util-buffer-from@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-buffer-from@npm:3.0.0" dependencies: + "@smithy/is-array-buffer": ^3.0.0 tslib: ^2.6.2 - checksum: 0f3f113c2658bd5a79f98dc28d53ca9c0adf8ec3c8c86c7dd91d2cd37149b4cf83d85cc89d5fe67ffe5cd319ec85f139ef229844eb039017193b307a4c315399 + checksum: 1bfc4ab093fe98132bbc1ccd36a0b9ad75a31ed26bac4b7e9350205513a2481eb190ae44679ab4fecc5e10d367b5e6592bbfbf792671579d17d17bd7f7f233f5 languageName: node linkType: hard -"@smithy/util-defaults-mode-browser@npm:^2.2.1": - version: 2.2.1 - resolution: "@smithy/util-defaults-mode-browser@npm:2.2.1" +"@smithy/util-config-provider@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-config-provider@npm:3.0.0" dependencies: - "@smithy/property-provider": ^2.2.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 + tslib: ^2.6.2 + checksum: fc0f5f57d30261cf3a6693d8e338b9d269332c478ee18d905309a769844188190caf0564855d7e84f6c61e56aa556195dda89f65e8c30791951cf4999e4a70e7 + languageName: node + linkType: hard + +"@smithy/util-defaults-mode-browser@npm:^3.0.4": + version: 3.0.6 + resolution: "@smithy/util-defaults-mode-browser@npm:3.0.6" + dependencies: + "@smithy/property-provider": ^3.1.2 + "@smithy/smithy-client": ^3.1.4 + "@smithy/types": ^3.2.0 bowser: ^2.11.0 tslib: ^2.6.2 - checksum: 286337d9165181e1df3d28d348210e88f20662ec63a9d6c1bcfce3342003de130a218dab42ce64aa4399ef345e2528414f73f399f8f4c8e9a6fcbc8e48250f98 + checksum: 753e21d8b6c9cbfb874dd9468823bce7ebfa979da8972fb5c67a31333513cebe09072fcb9ae803219bf41775569c8277e49f83abd96041042d3c487d299c7a0a languageName: node linkType: hard -"@smithy/util-defaults-mode-node@npm:^2.3.1": - version: 2.3.1 - resolution: "@smithy/util-defaults-mode-node@npm:2.3.1" +"@smithy/util-defaults-mode-node@npm:^3.0.4": + version: 3.0.6 + resolution: "@smithy/util-defaults-mode-node@npm:3.0.6" dependencies: - "@smithy/config-resolver": ^2.2.0 - "@smithy/credential-provider-imds": ^2.3.0 - "@smithy/node-config-provider": ^2.3.0 - "@smithy/property-provider": ^2.2.0 - "@smithy/smithy-client": ^2.5.1 - "@smithy/types": ^2.12.0 + "@smithy/config-resolver": ^3.0.3 + "@smithy/credential-provider-imds": ^3.1.2 + "@smithy/node-config-provider": ^3.1.2 + "@smithy/property-provider": ^3.1.2 + "@smithy/smithy-client": ^3.1.4 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 7fb9d0ac8b5919955399284c1801f49a1f5275f6cf240894ba0a91a8825248bb167938647a983d89905d6bfa7b226789781e85d2ff7f27c58cdd32c2e68600ae + checksum: d64efd2b5bd7b4b3b1a668725d34018bd8cae00b8a59991eadabf122e590ad153be4f9beda58b063b451d9f03371575c9a8e2806bcc0b7790e63fc9d839f5c95 languageName: node linkType: hard -"@smithy/util-endpoints@npm:^1.2.0": - version: 1.2.0 - resolution: "@smithy/util-endpoints@npm:1.2.0" +"@smithy/util-endpoints@npm:^2.0.2": + version: 2.0.3 + resolution: "@smithy/util-endpoints@npm:2.0.3" dependencies: - "@smithy/node-config-provider": ^2.3.0 - "@smithy/types": ^2.12.0 + "@smithy/node-config-provider": ^3.1.2 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 19a59b1c9b214457371d4d7109b190c237de5ebd06f5b4f3665dddc5fe0879dbb19bcdc5dec23d1825cd04388b7f9bf7fddf354e1a23e84d9c690ad21e71cb86 + checksum: f8b77a7f68bd99b73362b29a56e35270b509f76ed82c003e82dae1468f46c2c986060aea1fcb78f3d9346830f62c1c3f3e0aa4de856b8897ba183efabc22969d languageName: node linkType: hard -"@smithy/util-hex-encoding@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/util-hex-encoding@npm:2.2.0" +"@smithy/util-hex-encoding@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-hex-encoding@npm:3.0.0" dependencies: tslib: ^2.6.2 - checksum: 7d14589bc4a44eebf878595290c53ee4d90cc6b5445b5fe130608d6dea477c292730b85e4e08190a1555ef7664214f0f00dc478ba725516787a49fff658e725e + checksum: dd32fd71e915825987a18bf7c0f8f0c4956d0b17a0ee71592b5563bb20e04f24dbf81d36161aac07caab3bb5e535cc609fce20aa4a38f66b457c4c6f5c7748d9 languageName: node linkType: hard -"@smithy/util-middleware@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/util-middleware@npm:2.2.0" +"@smithy/util-middleware@npm:^3.0.1, @smithy/util-middleware@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/util-middleware@npm:3.0.2" dependencies: - "@smithy/types": ^2.12.0 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 312dc86e5415a12e2580a02311750b350aec8fb9da5a60c3010c10694990ded869b7ca5b87aa20e5facbacdd233e928e418b7765d7797019cd48177052aedd03 + checksum: 8a6183d3fd4a7c01787fbfd1dd901b1cdf0937f3c5e73646e8377b1e3322782e191cb7c1c9278e6c84d7462d4b0e70bcac9cfca52367728b3357914db96f90cc languageName: node linkType: hard -"@smithy/util-retry@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/util-retry@npm:2.2.0" +"@smithy/util-retry@npm:^3.0.1, @smithy/util-retry@npm:^3.0.2": + version: 3.0.2 + resolution: "@smithy/util-retry@npm:3.0.2" dependencies: - "@smithy/service-error-classification": ^2.1.5 - "@smithy/types": ^2.12.0 + "@smithy/service-error-classification": ^3.0.2 + "@smithy/types": ^3.2.0 tslib: ^2.6.2 - checksum: 1a8071c8ac5a2646b3d3894e3bd9c36a9db045f52eadb194f32b02d2fdedd69fb267a2b02bcef9f91d0f8f3fe061754ac075d07ac166d90894acb27d68c62a41 + checksum: 68846a52a6c71658db40f54681afad8c9bdb4687dc3c12fd13c27cf9aa3b96c57469a4d5658d4caabc9c710d95f920c0a3faafc9503fb99fb6466f51072fe852 languageName: node linkType: hard -"@smithy/util-stream@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/util-stream@npm:2.2.0" +"@smithy/util-stream@npm:^3.0.2, @smithy/util-stream@npm:^3.0.4": + version: 3.0.4 + resolution: "@smithy/util-stream@npm:3.0.4" dependencies: - "@smithy/fetch-http-handler": ^2.5.0 - "@smithy/node-http-handler": ^2.5.0 - "@smithy/types": ^2.12.0 - "@smithy/util-base64": ^2.3.0 - "@smithy/util-buffer-from": ^2.2.0 - "@smithy/util-hex-encoding": ^2.2.0 - "@smithy/util-utf8": ^2.3.0 + "@smithy/fetch-http-handler": ^3.1.0 + "@smithy/node-http-handler": ^3.1.0 + "@smithy/types": ^3.2.0 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-buffer-from": ^3.0.0 + "@smithy/util-hex-encoding": ^3.0.0 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: f0febd1a7558201d9178c0018478f89729800e9b8962dc735ec99f41ce01d1128373e3bd6008f0b4ff79b25ee4476db4fd5fa18d6feeb8b5b715d416da7027c3 + checksum: ba4a785d30606e82cbf80e644be05fad7a1813e19226ec8893a91993e0c943bc222643ab9c70625f72ee760b4f4d1632e74af586e028e7d3dc8197b1927e580b languageName: node linkType: hard @@ -15544,7 +15615,16 @@ __metadata: languageName: node linkType: hard -"@smithy/util-utf8@npm:^2.0.0, @smithy/util-utf8@npm:^2.3.0": +"@smithy/util-uri-escape@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-uri-escape@npm:3.0.0" + dependencies: + tslib: ^2.6.2 + checksum: d7ee01c978e2b08d0a89a3b678f5d5e5d5bb4ab4ab85567a238b1a6195dff1bdaf9ae62497e7f32ff5121b3dc007c370bcb6e8ef79b01fe5acdec5bbce8c7ce4 + languageName: node + linkType: hard + +"@smithy/util-utf8@npm:^2.0.0": version: 2.3.0 resolution: "@smithy/util-utf8@npm:2.3.0" dependencies: @@ -15554,14 +15634,24 @@ __metadata: languageName: node linkType: hard -"@smithy/util-waiter@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/util-waiter@npm:2.2.0" +"@smithy/util-utf8@npm:^3.0.0": + version: 3.0.0 + resolution: "@smithy/util-utf8@npm:3.0.0" dependencies: - "@smithy/abort-controller": ^2.2.0 - "@smithy/types": ^2.12.0 + "@smithy/util-buffer-from": ^3.0.0 tslib: ^2.6.2 - checksum: 303f56beb9ba4afada862eff4950a17d904a4fdfc01bd8acb932b0457e457730981162777004414252e700014c554d894a1ce9d32e0bad75e1a4a2ca6492429e + checksum: d97be1748963263a1161ba80417d82318b977b38542f3fdf0379b0162461188be680e5bfb66a89d65652f0fad6ecf2ab23a43205979216e50602488f73434da3 + languageName: node + linkType: hard + +"@smithy/util-waiter@npm:^3.0.1": + version: 3.1.1 + resolution: "@smithy/util-waiter@npm:3.1.1" + dependencies: + "@smithy/abort-controller": ^3.1.0 + "@smithy/types": ^3.2.0 + tslib: ^2.6.2 + checksum: dda2666bc0c91a158fdcd04eab41f01130b5d34a9d8a86ea5ed9a8d1c87829caf381fda34a0595bf4748e99365a36842afe12fbf045f532c55f0d14f49c6a448 languageName: node linkType: hard 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 274/860] 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 275/860] 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 276/860] 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 834ecd0c1e02f84c7f50e9ca72e7a44b8b38eeb1 Mon Sep 17 00:00:00 2001 From: Kevin L Date: Wed, 26 Jun 2024 19:21:25 -0400 Subject: [PATCH 277/860] Updated the AWS S3 integration docs Signed-off-by: Kevin L --- docs/integrations/aws-s3/discovery--old.md | 89 ++++++++++++++++++++++ docs/integrations/aws-s3/discovery.md | 26 +++---- 2 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 docs/integrations/aws-s3/discovery--old.md diff --git a/docs/integrations/aws-s3/discovery--old.md b/docs/integrations/aws-s3/discovery--old.md new file mode 100644 index 0000000000..bff63af9e5 --- /dev/null +++ b/docs/integrations/aws-s3/discovery--old.md @@ -0,0 +1,89 @@ +--- +id: discovery--old +title: AWS S3 Discovery +sidebar_label: Discovery +# prettier-ignore +description: Automatically discovering catalog entities from an AWS S3 Bucket +--- + +:::info +This documentation is written for the old backend which has been replaced by [the new backend system](../../backend-system/index.md), being the default since Backstage [version 1.24](../../releases/v1.24.0.md). If have migrated to the new backend system, you may want to read [its own article](./discovery.md) instead. Otherwise, [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + +The AWS S3 integration has a special entity provider for discovering catalog +entities located in an S3 Bucket. If you have a bucket that contains multiple +catalog files, and you want to automatically discover them, you can use this +provider. The provider will crawl your S3 bucket and register entities +matching the configured path. This can be useful as an alternative to static +locations or manually adding things to the catalog. + +To use the entity provider, you'll need an AWS S3 integration +[set up](locations.md) with `accessKeyId` and `secretAccessKey`, and/or +a `roleArn` or none of these (e.g., profile- or instance-based credentials). + +At production deployments, you likely manage these with the permissions attached +to your instance. + +In your configuration, you add a provider config per bucket: + +```yaml +# app-config.yaml + +catalog: + providers: + awsS3: + yourProviderId: # identifies your dataset / provider independent of config changes + bucketName: sample-bucket + prefix: prefix/ # optional + region: us-east-2 # optional, uses the default region otherwise + schedule: # same options as in TaskScheduleDefinition + # supports cron, ISO duration, "human duration" as used in code + frequency: { minutes: 30 } + # supports ISO duration, "human duration" as used in code + timeout: { minutes: 3 } +``` + +For simple setups, you can omit the provider ID at the config +which has the same effect as using `default` for it. + +```yaml +# app-config.yaml + +catalog: + providers: + awsS3: + # uses "default" as provider ID + bucketName: sample-bucket + prefix: prefix/ # optional + region: us-east-2 # optional, uses the default region otherwise + schedule: # same options as in TaskScheduleDefinition + # supports cron, ISO duration, "human duration" as used in code + frequency: { minutes: 30 } + # supports ISO duration, "human duration" as used in code + timeout: { minutes: 3 } +``` + +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 +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-aws +``` + +Once you've done that, you'll also need to add the segment below to `packages/backend/src/plugins/catalog.ts`: + +```ts +/* packages/backend/src/plugins/catalog.ts */ + +import { AwsS3EntityProvider } from '@backstage/plugin-catalog-backend-module-aws'; + +const builder = await CatalogBuilder.create(env); +/** ... other processors and/or providers ... */ +builder.addEntityProvider( + AwsS3EntityProvider.fromConfig(env.config, { + logger: env.logger, + scheduler: env.scheduler, + }), +); +``` diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md index d664466a16..cce410ea8b 100644 --- a/docs/integrations/aws-s3/discovery.md +++ b/docs/integrations/aws-s3/discovery.md @@ -6,6 +6,10 @@ sidebar_label: Discovery description: Automatically discovering catalog entities from an AWS S3 Bucket --- +:::info +This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./discovery--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + The AWS S3 integration has a special entity provider for discovering catalog entities located in an S3 Bucket. If you have a bucket that contains multiple catalog files, and you want to automatically discover them, you can use this @@ -20,7 +24,7 @@ a `roleArn` or none of these (e.g., profile- or instance-based credentials). At production deployments, you likely manage these with the permissions attached to your instance. -At your configuration, you add a provider config per bucket: +In your configuration, you add a provider config per bucket: ```yaml # app-config.yaml @@ -67,19 +71,11 @@ the AWS catalog plugin: yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-aws ``` -Once you've done that, you'll also need to add the segment below to `packages/backend/src/plugins/catalog.ts`: +Then update your backend by adding the following line: -```ts -/* packages/backend/src/plugins/catalog.ts */ - -import { AwsS3EntityProvider } from '@backstage/plugin-catalog-backend-module-aws'; - -const builder = await CatalogBuilder.create(env); -/** ... other processors and/or providers ... */ -builder.addEntityProvider( - AwsS3EntityProvider.fromConfig(env.config, { - logger: env.logger, - scheduler: env.scheduler, - }), -); +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-catalog-backend-module-aws/alpha')); +/* highlight-add-end */ ``` 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 278/860] 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 279/860] 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 280/860] 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 281/860] 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 282/860] 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 283/860] 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 284/860] 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 285/860] 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 286/860] 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 287/860] 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 288/860] 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 289/860] 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 290/860] 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 291/860] 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 db1cc30358eb629e0d6d380a174b0616ccfaede3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 13:16:04 +0000 Subject: [PATCH 292/860] fix(deps): update dependency @google-cloud/firestore to v7.9.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 97 +++++++++++++++++++------------------------------------ 1 file changed, 34 insertions(+), 63 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7c407dc27e..b8bffa5b78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9477,14 +9477,14 @@ __metadata: linkType: hard "@google-cloud/firestore@npm:^7.0.0": - version: 7.4.0 - resolution: "@google-cloud/firestore@npm:7.4.0" + version: 7.9.0 + resolution: "@google-cloud/firestore@npm:7.9.0" dependencies: fast-deep-equal: ^3.1.1 functional-red-black-tree: ^1.0.1 - google-gax: ^4.0.4 - protobufjs: ^7.2.5 - checksum: df0094c3be5473a96f925d7bcd4234f376e4928065bdd96bdc2debc73b4c976df160c2553dfc8ed3d73f859778996159e69770983fa0224a53afbe4e77754db3 + google-gax: ^4.3.3 + protobufjs: ^7.2.6 + checksum: 5d0657736f1e364cd110ea6083eb8b6aeb1605ea409ea5478d5c8430bfa568c62d472b41e892d0849dfb405b06d8aba412fd57a5d1e807429ba5264c48eb2673 languageName: node linkType: hard @@ -9862,27 +9862,17 @@ __metadata: languageName: node linkType: hard -"@grpc/grpc-js@npm:^1.7.1": - version: 1.10.7 - resolution: "@grpc/grpc-js@npm:1.10.7" +"@grpc/grpc-js@npm:^1.10.9, @grpc/grpc-js@npm:^1.7.1": + version: 1.10.10 + resolution: "@grpc/grpc-js@npm:1.10.10" dependencies: "@grpc/proto-loader": ^0.7.13 "@js-sdsl/ordered-map": ^4.4.2 - checksum: 69e88768e59b53ca020e2cfa9474fbd645f4ee7dd3269559c9fb91970273da6e8db480c0c439bdd73b49f1831d8f47c9bc5305dc5f9ed4db8873d53572e4f019 + checksum: e48274ab6e377031a2314197d33416c3261abf9601638ba05d8ae523e6e28338f97f852efdf9f9f763e49056812c83d3719cdf5913881d46cfca837dea2ab23c languageName: node linkType: hard -"@grpc/grpc-js@npm:~1.9.6": - version: 1.9.11 - resolution: "@grpc/grpc-js@npm:1.9.11" - dependencies: - "@grpc/proto-loader": ^0.7.8 - "@types/node": ">=12.12.47" - checksum: ed11ebcb0f8c34e2ada1d16ac2eef2465e1812871dd42bf40a405dfa06e2bfe895e680aff10644f9d51c33ce1ee1882ee466237ee478365c5ed265c0d7c5c015 - languageName: node - linkType: hard - -"@grpc/proto-loader@npm:^0.7.0, @grpc/proto-loader@npm:^0.7.13, @grpc/proto-loader@npm:^0.7.8": +"@grpc/proto-loader@npm:^0.7.13": version: 0.7.13 resolution: "@grpc/proto-loader@npm:0.7.13" dependencies: @@ -18164,7 +18154,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0, @types/node@npm:^20.1.1, @types/node@npm:^20.10.6, @types/node@npm:^20.11.16": +"@types/node@npm:*, @types/node@npm:>=13.7.0, @types/node@npm:^20.1.1, @types/node@npm:^20.10.6, @types/node@npm:^20.11.16": version: 20.12.7 resolution: "@types/node@npm:20.12.7" dependencies: @@ -28350,9 +28340,9 @@ __metadata: languageName: node linkType: hard -"google-auth-library@npm:^9.0.0, google-auth-library@npm:^9.6.3": - version: 9.8.0 - resolution: "google-auth-library@npm:9.8.0" +"google-auth-library@npm:^9.0.0, google-auth-library@npm:^9.3.0, google-auth-library@npm:^9.6.3": + version: 9.11.0 + resolution: "google-auth-library@npm:9.11.0" dependencies: base64-js: ^1.3.0 ecdsa-sig-formatter: ^1.0.11 @@ -28360,26 +28350,27 @@ __metadata: gcp-metadata: ^6.1.0 gtoken: ^7.0.0 jws: ^4.0.0 - checksum: dd67972861e16d47de494ac333bd76c57a5132e300793ae2dc8866fb76b3e57099846ce84b036ab2564bc4e85e0dc4d4cf245f4ca95aedebf53a9a2c03f35b38 + checksum: 984d344b5e0a21ea1e097d06e27173035619c0e8f89a363e538b445adb1414b79e938b56b4432aa36fda074c5922fa6a34f9b64734765c01dff73c45c8568554 languageName: node linkType: hard -"google-gax@npm:^4.0.3, google-gax@npm:^4.0.4": - version: 4.0.5 - resolution: "google-gax@npm:4.0.5" +"google-gax@npm:^4.0.3, google-gax@npm:^4.3.3": + version: 4.3.7 + resolution: "google-gax@npm:4.3.7" dependencies: - "@grpc/grpc-js": ~1.9.6 - "@grpc/proto-loader": ^0.7.0 + "@grpc/grpc-js": ^1.10.9 + "@grpc/proto-loader": ^0.7.13 "@types/long": ^4.0.0 abort-controller: ^3.0.0 duplexify: ^4.0.0 - google-auth-library: ^9.0.0 + google-auth-library: ^9.3.0 node-fetch: ^2.6.1 object-hash: ^3.0.0 - proto3-json-serializer: ^2.0.0 - protobufjs: 7.2.5 + proto3-json-serializer: ^2.0.2 + protobufjs: ^7.3.2 retry-request: ^7.0.0 - checksum: d4b5f2fc4a902b29d23552ab0fa498785ce88516ff07f7e7f08cac0f6572a78113a7f468f47b17e98d235d4049eeda8d77cfcad6291f6d14bda39b9eb19f935d + uuid: ^9.0.1 + checksum: f03327e42b5d0166c6655347c9ae56787a1cf0f2d32147530164f18deb808688e857e0017703d5b070c8b4ab9a003eda9598891b1cb5cdf007026be7a1c752d7 languageName: node linkType: hard @@ -37517,18 +37508,18 @@ __metadata: languageName: node linkType: hard -"proto3-json-serializer@npm:^2.0.0": - version: 2.0.0 - resolution: "proto3-json-serializer@npm:2.0.0" +"proto3-json-serializer@npm:^2.0.2": + version: 2.0.2 + resolution: "proto3-json-serializer@npm:2.0.2" dependencies: - protobufjs: ^7.0.0 - checksum: aea3433d5e0204625b97bda53001f71fc060eb83709d58d001c5bf75728f14b5ebfca39b54d81e7c90e4de363f68aecf1d203a410f33ebda9590a812f8f30b13 + protobufjs: ^7.2.5 + checksum: 21b8aa65be6dac2bb24920e5bdabef48b249bdf65b1498ae7e69ac4e70722275b083cd60a21d2b4be3ead9d768de2f6f5fb6b188bd177d51c824a539b5ba55cc languageName: node linkType: hard -"protobufjs@npm:7.2.5": - version: 7.2.5 - resolution: "protobufjs@npm:7.2.5" +"protobufjs@npm:^7.2.3, protobufjs@npm:^7.2.5, protobufjs@npm:^7.2.6, protobufjs@npm:^7.3.2": + version: 7.3.2 + resolution: "protobufjs@npm:7.3.2" dependencies: "@protobufjs/aspromise": ^1.1.2 "@protobufjs/base64": ^1.1.2 @@ -37542,27 +37533,7 @@ __metadata: "@protobufjs/utf8": ^1.1.0 "@types/node": ">=13.7.0" long: ^5.0.0 - checksum: 3770a072114061faebbb17cfd135bc4e187b66bc6f40cd8bac624368b0270871ec0cfb43a02b9fb4f029c8335808a840f1afba3c2e7ede7063b98ae6b98a703f - languageName: node - linkType: hard - -"protobufjs@npm:^7.0.0, protobufjs@npm:^7.2.3, protobufjs@npm:^7.2.5, protobufjs@npm:^7.2.6": - version: 7.2.6 - resolution: "protobufjs@npm:7.2.6" - dependencies: - "@protobufjs/aspromise": ^1.1.2 - "@protobufjs/base64": ^1.1.2 - "@protobufjs/codegen": ^2.0.4 - "@protobufjs/eventemitter": ^1.1.0 - "@protobufjs/fetch": ^1.1.0 - "@protobufjs/float": ^1.0.2 - "@protobufjs/inquire": ^1.1.0 - "@protobufjs/path": ^1.1.2 - "@protobufjs/pool": ^1.1.0 - "@protobufjs/utf8": ^1.1.0 - "@types/node": ">=13.7.0" - long: ^5.0.0 - checksum: 3c62e48f7d50017ac3b0dcd2a58e617cf858f9fba56a488bd48b9aa3482893a75540052dbcb3c12dfbaab42b1d04964611175faf06bdadcd33a4ebac982a511e + checksum: cfb2a744787f26ee7c82f3e7c4b72cfc000e9bb4c07828ed78eb414db0ea97a340c0cc3264d0e88606592f847b12c0351411f10e9af255b7ba864eec44d7705f 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 293/860] 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 294/860] 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 295/860] 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 296/860] 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 297/860] 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 298/860] 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 299/860] 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 300/860] 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 301/860] 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 302/860] 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 303/860] 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 304/860] 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 305/860] 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 306/860] 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 307/860] 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 308/860] 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 df955de8151075a32e5280bf3b137f160ca1edc0 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 17 Jun 2024 14:12:38 +0200 Subject: [PATCH 309/860] feat: add listBranchesByRepository method to BitbucketCloudClient Signed-off-by: Benjamin Janssens --- .../src/BitbucketCloudClient.ts | 20 +++++++++++++++++++ .../src/models/index.ts | 11 ++++++++++ 2 files changed, 31 insertions(+) diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts index f1b7d60e41..86f56dd70d 100644 --- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts +++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts @@ -95,6 +95,26 @@ export class BitbucketCloudClient { ); } + listBranchesByRepository( + repository: string, + workspace: string, + options?: FilterAndSortOptions & PartialResponseOptions, + ): WithPagination { + const workspaceEnc = encodeURIComponent(workspace); + + return new WithPagination( + paginationOptions => + this.createUrl( + `/repositories/${workspaceEnc}/${repository}/refs/branches`, + { + ...paginationOptions, + ...options, + }, + ), + url => this.getTypeMapped(url), + ); + } + private createUrl(endpoint: string, options?: RequestOptions): URL { const request = new URL(this.config.apiBaseUrl + endpoint); for (const key in options) { diff --git a/plugins/bitbucket-cloud-common/src/models/index.ts b/plugins/bitbucket-cloud-common/src/models/index.ts index 2cdc143d06..28b1b45e1b 100644 --- a/plugins/bitbucket-cloud-common/src/models/index.ts +++ b/plugins/bitbucket-cloud-common/src/models/index.ts @@ -275,6 +275,17 @@ export namespace Models { values?: Set; } + /** + * A paginated list of branches. + * @public + */ + export interface PaginatedBranches extends Paginated { + /** + * The values of the current page. + */ + values?: Set; + } + /** * Object describing a user's role on resources like commits or pull requests. * @public From 7ee5682ad467090c3cb99866968a1efddfef1eb9 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 17 Jun 2024 14:18:07 +0200 Subject: [PATCH 310/860] feat: add branches resource to autocomplete endpoint for bitbucket Signed-off-by: Benjamin Janssens --- .../src/autocomplete/autocomplete.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts index 31a2103088..70824995ac 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts @@ -77,6 +77,23 @@ export async function handleAutocompleteRequest({ return { results: result.map(title => ({ title })) }; } + case 'branches': { + if (!parameters.workspace || !parameters.repository) + throw new InputError( + 'Missing workspace and/or repository query parameter', + ); + + const result: string[] = []; + + for await (const page of client + .listBranchesByRepository(parameters.repository, parameters.workspace) + .iteratePages()) { + const names = [...page.values!].map(p => p.name!); + result.push(...names); + } + + return result; + } default: throw new InputError(`Invalid resource: ${resource}`); } From f6fea341737fd8e1820d882b5c4eeb2c2d4abb25 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 17 Jun 2024 16:32:15 +0200 Subject: [PATCH 311/860] feat: add BitbucketRepoBranchPicker Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.tsx | 145 ++++++++++++++++++ .../fields/BitbucketRepoBranchPicker/index.ts | 20 +++ .../BitbucketRepoBranchPicker/schema.ts | 82 ++++++++++ plugins/scaffolder/src/extensions/default.ts | 7 + plugins/scaffolder/src/index.ts | 1 + plugins/scaffolder/src/plugin.tsx | 15 ++ 6 files changed, 270 insertions(+) create mode 100644 plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx create mode 100644 plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts create mode 100644 plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx new file mode 100644 index 0000000000..df496516af --- /dev/null +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -0,0 +1,145 @@ +/* + * 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 { + scaffolderApiRef, + useTemplateSecrets, +} from '@backstage/plugin-scaffolder-react'; +import FormControl from '@material-ui/core/FormControl'; +import React, { useEffect, useMemo, useState } from 'react'; +import TextField from '@material-ui/core/TextField'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import useDebounce from 'react-use/esm/useDebounce'; +import { useApi } from '@backstage/core-plugin-api'; +import { scmAuthApiRef } from '@backstage/integration-react'; +import { BitbucketRepoBranchPickerProps } from './schema'; + +export const BitbucketRepoBranchPicker = ({ + onChange, + rawErrors, + required, + formData, + formContext: { + formData: { repoUrl }, + }, + uiSchema, +}: BitbucketRepoBranchPickerProps) => { + const { secrets, setSecrets } = useTemplateSecrets(); + + const accessToken = useMemo( + () => + uiSchema?.['ui:options']?.requestUserCredentials?.secretsKey && + secrets[uiSchema['ui:options'].requestUserCredentials.secretsKey], + [secrets, uiSchema], + ); + + const [host, setHost] = useState(); + const [workspace, setWorkspace] = useState(null); + const [repository, setRepository] = useState(null); + const [availableBranches, setAvailableBranches] = useState([]); + + const scmAuthApi = useApi(scmAuthApiRef); + const scaffolderApi = useApi(scaffolderApiRef); + + useEffect(() => { + if (repoUrl) { + const url = new URL(`https://${repoUrl}`); + setHost(url.host); + setWorkspace(url.searchParams.get('workspace')); + setRepository(url.searchParams.get('repo')); + } + }, [repoUrl]); + + useDebounce( + async () => { + const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {}; + + if (!requestUserCredentials || !host) { + return; + } + + // don't show login prompt if secret value is already in state + if (secrets[requestUserCredentials.secretsKey]) { + return; + } + + // user has requested that we use the users credentials + // so lets grab them using the scmAuthApi and pass through + // any additional scopes from the ui:options + const { token } = await scmAuthApi.getCredentials({ + url: `https://${host}`, + additionalScope: { + repoWrite: true, + customScopes: requestUserCredentials.additionalScopes, + }, + }); + + // 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 }); + }, + 500, + [host, uiSchema], + ); + + useDebounce( + () => { + const updateAvailableBranches = async () => { + if ( + host === 'bitbucket.org' && + accessToken && + workspace && + repository + ) { + const result = await scaffolderApi.autocomplete( + accessToken, + 'bitbucketCloud', + 'branches', + { workspace, repository }, + ); + + setAvailableBranches(result); + } else { + setAvailableBranches([]); + } + }; + + updateAvailableBranches().catch(() => setAvailableBranches([])); + }, + 500, + [host, accessToken, workspace, repository], + ); + + return ( + 0 && !formData} + > + { + onChange(newValue || ''); + }} + options={availableBranches} + renderInput={params => ( + + )} + freeSolo + autoSelect + /> + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts new file mode 100644 index 0000000000..df9acbd8b9 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export { + BitbucketRepoBranchPickerFieldSchema, + type BitbucketRepoBranchPickerUiOptions, +} from './schema'; diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts new file mode 100644 index 0000000000..3e14888ed5 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts @@ -0,0 +1,82 @@ +/* + * 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 { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; + +/** + * @public + */ +export const BitbucketRepoBranchPickerFieldSchema = makeFieldSchemaFromZod( + z.string(), + z.object({ + requestUserCredentials: z + .object({ + secretsKey: z + .string() + .describe( + 'Key used within the template secrets context to store the credential', + ), + additionalScopes: z + .object({ + gitea: z + .array(z.string()) + .optional() + .describe('Additional Gitea scopes to request'), + gerrit: z + .array(z.string()) + .optional() + .describe('Additional Gerrit scopes to request'), + github: z + .array(z.string()) + .optional() + .describe('Additional GitHub scopes to request'), + gitlab: z + .array(z.string()) + .optional() + .describe('Additional GitLab scopes to request'), + bitbucket: z + .array(z.string()) + .optional() + .describe('Additional BitBucket scopes to request'), + azure: z + .array(z.string()) + .optional() + .describe('Additional Azure scopes to request'), + }) + .optional() + .describe('Additional permission scopes to request'), + }) + .optional() + .describe( + 'If defined will request user credentials to auth against the given SCM platform', + ), + }), +); + +/** + * The input props that can be specified under `ui:options` for the + * `BitbucketRepoBranchPicker` field extension. + * + * @public + */ +export type BitbucketRepoBranchPickerUiOptions = + typeof BitbucketRepoBranchPickerFieldSchema.uiOptionsType; + +export type BitbucketRepoBranchPickerProps = + typeof BitbucketRepoBranchPickerFieldSchema.type; + +export const BitbucketRepoBranchPickerSchema = + BitbucketRepoBranchPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index a59f3e08e3..13a719e9f9 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -50,6 +50,8 @@ import { MultiEntityPickerSchema, validateMultiEntityPickerValidation, } from '../components/fields/MultiEntityPicker/MultiEntityPicker'; +import { BitbucketRepoBranchPicker } from '../components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker'; +import { BitbucketRepoBranchPickerSchema } from '../components/fields/BitbucketRepoBranchPicker/schema'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ { @@ -99,4 +101,9 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ schema: MultiEntityPickerSchema, validation: validateMultiEntityPickerValidation, }, + { + component: BitbucketRepoBranchPicker, + name: 'BitbucketRepoBranchPicker', + schema: BitbucketRepoBranchPickerSchema, + }, ]; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index d809ec00f9..d343311db9 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -30,6 +30,7 @@ export { MyGroupsPickerFieldExtension, RepoUrlPickerFieldExtension, MultiEntityPickerFieldExtension, + BitbucketRepoBranchPickerFieldExtension, ScaffolderPage, scaffolderPlugin, } from './plugin'; diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index c053bfacd9..453e5ea63a 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -73,6 +73,8 @@ import { MyGroupsPicker, MyGroupsPickerSchema, } from './components/fields/MyGroupsPicker/MyGroupsPicker'; +import { BitbucketRepoBranchPicker } from './components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker'; +import { BitbucketRepoBranchPickerSchema } from './components/fields/BitbucketRepoBranchPicker/schema'; /** * The main plugin export for the scaffolder. @@ -231,3 +233,16 @@ export const EntityTagsPickerFieldExtension = scaffolderPlugin.provide( schema: EntityTagsPickerSchema, }), ); + +/** + * A field extension to select a branch from a repository. + * + * @public + */ +export const BitbucketRepoBranchPickerFieldExtension = scaffolderPlugin.provide( + createScaffolderFieldExtension({ + component: BitbucketRepoBranchPicker, + name: 'BitbucketRepoBranchPicker', + schema: BitbucketRepoBranchPickerSchema, + }), +); From 741837a560f16369b3aadce4294e02726e5732e8 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 18 Jun 2024 11:42:20 +0200 Subject: [PATCH 312/860] refactor: add generic RepoBranchPicker Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.tsx | 109 ++++----------- .../RepoBranchPicker.tsx | 125 ++++++++++++++++++ .../fields/BitbucketRepoBranchPicker/index.ts | 4 +- .../BitbucketRepoBranchPicker/schema.ts | 14 +- .../fields/BitbucketRepoBranchPicker/types.ts | 23 ++++ plugins/scaffolder/src/extensions/default.ts | 10 +- plugins/scaffolder/src/index.ts | 2 +- plugins/scaffolder/src/plugin.tsx | 12 +- 8 files changed, 194 insertions(+), 105 deletions(-) create mode 100644 plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx create mode 100644 plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx index df496516af..736841b7a6 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -14,128 +14,71 @@ * limitations under the License. */ -import { - scaffolderApiRef, - useTemplateSecrets, -} from '@backstage/plugin-scaffolder-react'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import FormControl from '@material-ui/core/FormControl'; -import React, { useEffect, useMemo, useState } from 'react'; +import React from 'react'; import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; import useDebounce from 'react-use/esm/useDebounce'; import { useApi } from '@backstage/core-plugin-api'; -import { scmAuthApiRef } from '@backstage/integration-react'; -import { BitbucketRepoBranchPickerProps } from './schema'; +import { RepoBranchPickerState } from './types'; export const BitbucketRepoBranchPicker = ({ onChange, + state, rawErrors, - required, - formData, - formContext: { - formData: { repoUrl }, - }, - uiSchema, -}: BitbucketRepoBranchPickerProps) => { - const { secrets, setSecrets } = useTemplateSecrets(); - - const accessToken = useMemo( - () => - uiSchema?.['ui:options']?.requestUserCredentials?.secretsKey && - secrets[uiSchema['ui:options'].requestUserCredentials.secretsKey], - [secrets, uiSchema], - ); - - const [host, setHost] = useState(); - const [workspace, setWorkspace] = useState(null); - const [repository, setRepository] = useState(null); - const [availableBranches, setAvailableBranches] = useState([]); - - const scmAuthApi = useApi(scmAuthApiRef); + accessToken, +}: { + onChange: (state: RepoBranchPickerState) => void; + state: RepoBranchPickerState; + rawErrors: string[]; + accessToken?: string; +}) => { const scaffolderApi = useApi(scaffolderApiRef); - useEffect(() => { - if (repoUrl) { - const url = new URL(`https://${repoUrl}`); - setHost(url.host); - setWorkspace(url.searchParams.get('workspace')); - setRepository(url.searchParams.get('repo')); - } - }, [repoUrl]); - - useDebounce( - async () => { - const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {}; - - if (!requestUserCredentials || !host) { - return; - } - - // don't show login prompt if secret value is already in state - if (secrets[requestUserCredentials.secretsKey]) { - return; - } - - // user has requested that we use the users credentials - // so lets grab them using the scmAuthApi and pass through - // any additional scopes from the ui:options - const { token } = await scmAuthApi.getCredentials({ - url: `https://${host}`, - additionalScope: { - repoWrite: true, - customScopes: requestUserCredentials.additionalScopes, - }, - }); - - // 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 }); - }, - 500, - [host, uiSchema], - ); - useDebounce( () => { const updateAvailableBranches = async () => { if ( - host === 'bitbucket.org' && + state.host === 'bitbucket.org' && accessToken && - workspace && - repository + state.workspace && + state.repository ) { const result = await scaffolderApi.autocomplete( accessToken, 'bitbucketCloud', 'branches', - { workspace, repository }, + { workspace: state.workspace, repository: state.repository }, ); - setAvailableBranches(result); + onChange({ availableBranches: result }); } else { - setAvailableBranches([]); + onChange({ availableBranches: [] }); } }; - updateAvailableBranches().catch(() => setAvailableBranches([])); + updateAvailableBranches().catch(() => + onChange({ availableBranches: [] }), + ); }, 500, - [host, accessToken, workspace, repository], + [state, accessToken], ); return ( 0 && !formData} + required + error={rawErrors?.length > 0 && !state.branch} > { - onChange(newValue || ''); + onChange({ branch: newValue || undefined }); }} - options={availableBranches} + options={state.availableBranches || []} renderInput={params => ( - + )} freeSolo autoSelect diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx new file mode 100644 index 0000000000..1f75090e3b --- /dev/null +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx @@ -0,0 +1,125 @@ +/* + * 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 { useApi } from '@backstage/core-plugin-api'; +import { + scmIntegrationsApiRef, + scmAuthApiRef, +} from '@backstage/integration-react'; +import React, { useEffect, useState, useCallback } from 'react'; +import { RepoBranchPickerProps } from './schema'; +import { RepoBranchPickerState } from './types'; +import useDebounce from 'react-use/esm/useDebounce'; +import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react'; +import Box from '@material-ui/core/Box'; +import Divider from '@material-ui/core/Divider'; +import Typography from '@material-ui/core/Typography'; +import { BitbucketRepoBranchPicker } from './BitbucketRepoBranchPicker'; + +/** + * The underlying component that is rendered in the form for the `RepoBranchPicker` + * field extension. + * + * @public + */ +export const RepoBranchPicker = (props: RepoBranchPickerProps) => { + const { uiSchema, onChange, rawErrors, schema, formContext } = props; + const [state, setState] = useState({}); + const integrationApi = useApi(scmIntegrationsApiRef); + const scmAuthApi = useApi(scmAuthApiRef); + const { secrets, setSecrets } = useTemplateSecrets(); + + useEffect(() => { + if (formContext.formData.repoUrl) { + const url = new URL(`https://${formContext.formData.repoUrl}`); + + setState({ + host: url.host, + workspace: url.searchParams.get('workspace') || undefined, + repository: url.searchParams.get('repo') || undefined, + }); + } + }, [formContext]); + + useEffect(() => { + onChange(state.branch); + }, [state, onChange]); + + const updateLocalState = useCallback( + (newState: RepoBranchPickerState) => { + setState(prevState => ({ ...prevState, ...newState })); + }, + [setState], + ); + + useDebounce( + async () => { + const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {}; + + if (!requestUserCredentials || !state.host) { + return; + } + + // don't show login prompt if secret value is already in state + if (secrets[requestUserCredentials.secretsKey]) { + return; + } + + // user has requested that we use the users credentials + // so lets grab them using the scmAuthApi and pass through + // any additional scopes from the ui:options + const { token } = await scmAuthApi.getCredentials({ + url: `https://${state.host}`, + additionalScope: { + repoWrite: true, + customScopes: requestUserCredentials.additionalScopes, + }, + }); + + // 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 }); + }, + 500, + [state, uiSchema], + ); + + const hostType = + (state.host && integrationApi.byHost(state.host)?.type) ?? null; + return ( + <> + {schema.title && ( + + {schema.title} + + + )} + {schema.description && ( + {schema.description} + )} + {hostType === 'bitbucket' && ( + + )} + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts index df9acbd8b9..2b87b62ebd 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts @@ -15,6 +15,6 @@ */ export { - BitbucketRepoBranchPickerFieldSchema, - type BitbucketRepoBranchPickerUiOptions, + RepoBranchPickerFieldSchema, + type RepoBranchPickerUiOptions, } from './schema'; diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts index 3e14888ed5..12ed07fd80 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts @@ -19,7 +19,7 @@ import { makeFieldSchemaFromZod } from '../utils'; /** * @public */ -export const BitbucketRepoBranchPickerFieldSchema = makeFieldSchemaFromZod( +export const RepoBranchPickerFieldSchema = makeFieldSchemaFromZod( z.string(), z.object({ requestUserCredentials: z @@ -68,15 +68,13 @@ export const BitbucketRepoBranchPickerFieldSchema = makeFieldSchemaFromZod( /** * The input props that can be specified under `ui:options` for the - * `BitbucketRepoBranchPicker` field extension. + * `RepoBranchPicker` field extension. * * @public */ -export type BitbucketRepoBranchPickerUiOptions = - typeof BitbucketRepoBranchPickerFieldSchema.uiOptionsType; +export type RepoBranchPickerUiOptions = + typeof RepoBranchPickerFieldSchema.uiOptionsType; -export type BitbucketRepoBranchPickerProps = - typeof BitbucketRepoBranchPickerFieldSchema.type; +export type RepoBranchPickerProps = typeof RepoBranchPickerFieldSchema.type; -export const BitbucketRepoBranchPickerSchema = - BitbucketRepoBranchPickerFieldSchema.schema; +export const RepoBranchPickerSchema = RepoBranchPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts new file mode 100644 index 0000000000..4843ff767e --- /dev/null +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export interface RepoBranchPickerState { + host?: string; + workspace?: string; + repository?: string; + branch?: string; + availableBranches?: string[]; +} diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index 13a719e9f9..409372e421 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -50,8 +50,8 @@ import { MultiEntityPickerSchema, validateMultiEntityPickerValidation, } from '../components/fields/MultiEntityPicker/MultiEntityPicker'; -import { BitbucketRepoBranchPicker } from '../components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker'; -import { BitbucketRepoBranchPickerSchema } from '../components/fields/BitbucketRepoBranchPicker/schema'; +import { RepoBranchPicker } from '../components/fields/BitbucketRepoBranchPicker/RepoBranchPicker'; +import { RepoBranchPickerSchema } from '../components/fields/BitbucketRepoBranchPicker/schema'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ { @@ -102,8 +102,8 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ validation: validateMultiEntityPickerValidation, }, { - component: BitbucketRepoBranchPicker, - name: 'BitbucketRepoBranchPicker', - schema: BitbucketRepoBranchPickerSchema, + component: RepoBranchPicker, + name: 'RepoBranchPicker', + schema: RepoBranchPickerSchema, }, ]; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index d343311db9..c5709f1080 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -30,7 +30,7 @@ export { MyGroupsPickerFieldExtension, RepoUrlPickerFieldExtension, MultiEntityPickerFieldExtension, - BitbucketRepoBranchPickerFieldExtension, + RepoBranchPickerFieldExtension, ScaffolderPage, scaffolderPlugin, } from './plugin'; diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index 453e5ea63a..6f4e28c9b0 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -73,8 +73,8 @@ import { MyGroupsPicker, MyGroupsPickerSchema, } from './components/fields/MyGroupsPicker/MyGroupsPicker'; -import { BitbucketRepoBranchPicker } from './components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker'; -import { BitbucketRepoBranchPickerSchema } from './components/fields/BitbucketRepoBranchPicker/schema'; +import { RepoBranchPicker } from './components/fields/BitbucketRepoBranchPicker/RepoBranchPicker'; +import { RepoBranchPickerSchema } from './components/fields/BitbucketRepoBranchPicker/schema'; /** * The main plugin export for the scaffolder. @@ -239,10 +239,10 @@ export const EntityTagsPickerFieldExtension = scaffolderPlugin.provide( * * @public */ -export const BitbucketRepoBranchPickerFieldExtension = scaffolderPlugin.provide( +export const RepoBranchPickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ - component: BitbucketRepoBranchPicker, - name: 'BitbucketRepoBranchPicker', - schema: BitbucketRepoBranchPickerSchema, + component: RepoBranchPicker, + name: 'RepoBranchPicker', + schema: RepoBranchPickerSchema, }), ); From 3a272ac051baf5be2417be598a591859f4ef30b3 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 18 Jun 2024 11:54:00 +0200 Subject: [PATCH 313/860] chore: code cleanup Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.tsx | 14 ++--- .../RepoBranchPicker.tsx | 54 ++++++++++--------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx index 736841b7a6..70f4ea8c36 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -34,22 +34,24 @@ export const BitbucketRepoBranchPicker = ({ rawErrors: string[]; accessToken?: string; }) => { + const { host, workspace, repository, branch, availableBranches } = state; + const scaffolderApi = useApi(scaffolderApiRef); useDebounce( () => { const updateAvailableBranches = async () => { if ( - state.host === 'bitbucket.org' && + host === 'bitbucket.org' && accessToken && - state.workspace && - state.repository + workspace && + repository ) { const result = await scaffolderApi.autocomplete( accessToken, 'bitbucketCloud', 'branches', - { workspace: state.workspace, repository: state.repository }, + { workspace, repository }, ); onChange({ availableBranches: result }); @@ -70,13 +72,13 @@ export const BitbucketRepoBranchPicker = ({ 0 && !state.branch} + error={rawErrors?.length > 0 && !branch} > { onChange({ branch: newValue || undefined }); }} - options={state.availableBranches || []} + options={availableBranches || []} renderInput={params => ( )} diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx index 1f75090e3b..c690a58f4a 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx @@ -36,34 +36,15 @@ import { BitbucketRepoBranchPicker } from './BitbucketRepoBranchPicker'; */ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { const { uiSchema, onChange, rawErrors, schema, formContext } = props; + const [state, setState] = useState({}); + const { host, branch } = state; + const integrationApi = useApi(scmIntegrationsApiRef); const scmAuthApi = useApi(scmAuthApiRef); + const { secrets, setSecrets } = useTemplateSecrets(); - useEffect(() => { - if (formContext.formData.repoUrl) { - const url = new URL(`https://${formContext.formData.repoUrl}`); - - setState({ - host: url.host, - workspace: url.searchParams.get('workspace') || undefined, - repository: url.searchParams.get('repo') || undefined, - }); - } - }, [formContext]); - - useEffect(() => { - onChange(state.branch); - }, [state, onChange]); - - const updateLocalState = useCallback( - (newState: RepoBranchPickerState) => { - setState(prevState => ({ ...prevState, ...newState })); - }, - [setState], - ); - useDebounce( async () => { const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {}; @@ -96,8 +77,31 @@ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { [state, uiSchema], ); - const hostType = - (state.host && integrationApi.byHost(state.host)?.type) ?? null; + useEffect(() => { + if (formContext.formData.repoUrl) { + const url = new URL(`https://${formContext.formData.repoUrl}`); + + setState({ + host: url.host, + workspace: url.searchParams.get('workspace') || undefined, + repository: url.searchParams.get('repo') || undefined, + }); + } + }, [formContext]); + + useEffect(() => { + onChange(branch); + }, [branch, onChange]); + + const updateLocalState = useCallback( + (newState: RepoBranchPickerState) => { + setState(prevState => ({ ...prevState, ...newState })); + }, + [setState], + ); + + const hostType = (host && integrationApi.byHost(host)?.type) ?? null; + return ( <> {schema.title && ( From 4e3ba7ca74ed3e675e607ceb88d0c1759b65442d Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 18 Jun 2024 13:37:38 +0200 Subject: [PATCH 314/860] chore: code cleanup Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.tsx | 7 ++-- .../RepoBranchPicker.tsx | 32 ++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx index 70f4ea8c36..27a0b5c027 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -22,6 +22,7 @@ import Autocomplete from '@material-ui/lab/Autocomplete'; import useDebounce from 'react-use/esm/useDebounce'; import { useApi } from '@backstage/core-plugin-api'; import { RepoBranchPickerState } from './types'; +import FormHelperText from '@material-ui/core/FormHelperText'; export const BitbucketRepoBranchPicker = ({ onChange, @@ -65,7 +66,7 @@ export const BitbucketRepoBranchPicker = ({ ); }, 500, - [state, accessToken], + [host, workspace, repository, accessToken], ); return ( @@ -75,8 +76,9 @@ export const BitbucketRepoBranchPicker = ({ error={rawErrors?.length > 0 && !branch} > { - onChange({ branch: newValue || undefined }); + onChange({ branch: newValue || '' }); }} options={availableBranches || []} renderInput={params => ( @@ -85,6 +87,7 @@ export const BitbucketRepoBranchPicker = ({ freeSolo autoSelect /> + The branch of the repository ); }; diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx index c690a58f4a..2ba1eddbfc 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { useApi } from '@backstage/core-plugin-api'; import { scmIntegrationsApiRef, @@ -35,9 +36,15 @@ import { BitbucketRepoBranchPicker } from './BitbucketRepoBranchPicker'; * @public */ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { - const { uiSchema, onChange, rawErrors, schema, formContext } = props; + const { uiSchema, onChange, rawErrors, formData, schema, formContext } = + props; + const { + formData: { repoUrl }, + } = formContext; - const [state, setState] = useState({}); + const [state, setState] = useState({ + branch: formData || '', + }); const { host, branch } = state; const integrationApi = useApi(scmIntegrationsApiRef); @@ -49,7 +56,7 @@ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { async () => { const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {}; - if (!requestUserCredentials || !state.host) { + if (!requestUserCredentials || !host) { return; } @@ -62,7 +69,7 @@ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { // so lets grab them using the scmAuthApi and pass through // any additional scopes from the ui:options const { token } = await scmAuthApi.getCredentials({ - url: `https://${state.host}`, + url: `https://${host}`, additionalScope: { repoWrite: true, customScopes: requestUserCredentials.additionalScopes, @@ -74,20 +81,21 @@ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { setSecrets({ [requestUserCredentials.secretsKey]: token }); }, 500, - [state, uiSchema], + [host, uiSchema], ); useEffect(() => { - if (formContext.formData.repoUrl) { - const url = new URL(`https://${formContext.formData.repoUrl}`); + if (repoUrl) { + const url = new URL(`https://${repoUrl}`); - setState({ + setState(prevState => ({ + ...prevState, host: url.host, - workspace: url.searchParams.get('workspace') || undefined, - repository: url.searchParams.get('repo') || undefined, - }); + workspace: url.searchParams.get('workspace') || '', + repository: url.searchParams.get('repo') || '', + })); } - }, [formContext]); + }, [repoUrl]); useEffect(() => { onChange(branch); From fb528a9196450b09667950fa293108ce7f83dca4 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 18 Jun 2024 14:44:12 +0200 Subject: [PATCH 315/860] refactor: move availableBranches from RepoBranchPickerState to BitbucketRepoBranchPicker; add tests for BitbucketRepoBranchPicker Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.test.tsx | 105 ++++++++++++++++++ .../BitbucketRepoBranchPicker.tsx | 16 +-- .../fields/BitbucketRepoBranchPicker/types.ts | 1 - 3 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.test.tsx diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.test.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.test.tsx new file mode 100644 index 0000000000..6cbc561bc9 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.test.tsx @@ -0,0 +1,105 @@ +/* + * 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 { + ScaffolderApi, + scaffolderApiRef, +} from '@backstage/plugin-scaffolder-react'; +import { BitbucketRepoBranchPicker } from './BitbucketRepoBranchPicker'; +import { act, fireEvent, render, waitFor } from '@testing-library/react'; +import { TestApiProvider } from '@backstage/test-utils'; +import userEvent from '@testing-library/user-event'; + +describe('BitbucketRepoBranchPicker', () => { + const scaffolderApiMock: Partial = { + autocomplete: jest.fn().mockResolvedValue(['branch1']), + }; + + it('renders an input field', () => { + const { getByRole } = render( + + + , + ); + + expect(getByRole('textbox')).toBeInTheDocument(); + expect(getByRole('textbox')).toHaveValue('main'); + }); + + it('calls onChange when the input field changes', () => { + const onChange = jest.fn(); + + const { getByRole } = render( + + + , + ); + + const input = getByRole('textbox'); + + act(() => { + input.focus(); + fireEvent.change(input, { + target: { value: 'develop' }, + }); + input.blur(); + }); + + expect(onChange).toHaveBeenCalledWith({ branch: 'develop' }); + }); + + it('should populate branches', async () => { + const onChange = jest.fn(); + + const { getByRole, getByText } = render( + + + , + ); + + // Open the Autcomplete dropdown + const input = getByRole('textbox'); + await userEvent.click(input); + + // Verify that the available workspaces are shown + await waitFor(() => expect(getByText('branch1')).toBeInTheDocument()); + + // Verify that selecting an option calls onChange + await userEvent.click(getByText('branch1')); + expect(onChange).toHaveBeenCalledWith({ + branch: 'branch1', + }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx index 27a0b5c027..3af7eb7e2c 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -16,7 +16,7 @@ import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import FormControl from '@material-ui/core/FormControl'; -import React from 'react'; +import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; import useDebounce from 'react-use/esm/useDebounce'; @@ -35,7 +35,9 @@ export const BitbucketRepoBranchPicker = ({ rawErrors: string[]; accessToken?: string; }) => { - const { host, workspace, repository, branch, availableBranches } = state; + const { host, workspace, repository, branch } = state; + + const [availableBranches, setAvailableBranches] = useState([]); const scaffolderApi = useApi(scaffolderApiRef); @@ -55,15 +57,13 @@ export const BitbucketRepoBranchPicker = ({ { workspace, repository }, ); - onChange({ availableBranches: result }); + setAvailableBranches(result); } else { - onChange({ availableBranches: [] }); + setAvailableBranches([]); } }; - updateAvailableBranches().catch(() => - onChange({ availableBranches: [] }), - ); + updateAvailableBranches().catch(() => setAvailableBranches([])); }, 500, [host, workspace, repository, accessToken], @@ -80,7 +80,7 @@ export const BitbucketRepoBranchPicker = ({ onChange={(_, newValue) => { onChange({ branch: newValue || '' }); }} - options={availableBranches || []} + options={availableBranches} renderInput={params => ( )} diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts index 4843ff767e..1d54ea7e8b 100644 --- a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts +++ b/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts @@ -19,5 +19,4 @@ export interface RepoBranchPickerState { workspace?: string; repository?: string; branch?: string; - availableBranches?: string[]; } From a781cd8513b9ec3a86bcb2379be7fbc5b5a49d2c Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 18 Jun 2024 14:46:20 +0200 Subject: [PATCH 316/860] chore: rename BitbucketRepoBranchPicker folder to RepoBranchPicker Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.test.tsx | 0 .../BitbucketRepoBranchPicker.tsx | 0 .../RepoBranchPicker.tsx | 0 .../{BitbucketRepoBranchPicker => RepoBranchPicker}/index.ts | 0 .../{BitbucketRepoBranchPicker => RepoBranchPicker}/schema.ts | 0 .../{BitbucketRepoBranchPicker => RepoBranchPicker}/types.ts | 0 plugins/scaffolder/src/extensions/default.ts | 4 ++-- plugins/scaffolder/src/plugin.tsx | 4 ++-- 8 files changed, 4 insertions(+), 4 deletions(-) rename plugins/scaffolder/src/components/fields/{BitbucketRepoBranchPicker => RepoBranchPicker}/BitbucketRepoBranchPicker.test.tsx (100%) rename plugins/scaffolder/src/components/fields/{BitbucketRepoBranchPicker => RepoBranchPicker}/BitbucketRepoBranchPicker.tsx (100%) rename plugins/scaffolder/src/components/fields/{BitbucketRepoBranchPicker => RepoBranchPicker}/RepoBranchPicker.tsx (100%) rename plugins/scaffolder/src/components/fields/{BitbucketRepoBranchPicker => RepoBranchPicker}/index.ts (100%) rename plugins/scaffolder/src/components/fields/{BitbucketRepoBranchPicker => RepoBranchPicker}/schema.ts (100%) rename plugins/scaffolder/src/components/fields/{BitbucketRepoBranchPicker => RepoBranchPicker}/types.ts (100%) diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.test.tsx rename to plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.test.tsx diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx similarity index 100% rename from plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/BitbucketRepoBranchPicker.tsx rename to plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx similarity index 100% rename from plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/RepoBranchPicker.tsx rename to plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts b/plugins/scaffolder/src/components/fields/RepoBranchPicker/index.ts similarity index 100% rename from plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/index.ts rename to plugins/scaffolder/src/components/fields/RepoBranchPicker/index.ts diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts b/plugins/scaffolder/src/components/fields/RepoBranchPicker/schema.ts similarity index 100% rename from plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/schema.ts rename to plugins/scaffolder/src/components/fields/RepoBranchPicker/schema.ts diff --git a/plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts b/plugins/scaffolder/src/components/fields/RepoBranchPicker/types.ts similarity index 100% rename from plugins/scaffolder/src/components/fields/BitbucketRepoBranchPicker/types.ts rename to plugins/scaffolder/src/components/fields/RepoBranchPicker/types.ts diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index 409372e421..e77d968c80 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -50,8 +50,8 @@ import { MultiEntityPickerSchema, validateMultiEntityPickerValidation, } from '../components/fields/MultiEntityPicker/MultiEntityPicker'; -import { RepoBranchPicker } from '../components/fields/BitbucketRepoBranchPicker/RepoBranchPicker'; -import { RepoBranchPickerSchema } from '../components/fields/BitbucketRepoBranchPicker/schema'; +import { RepoBranchPicker } from '../components/fields/RepoBranchPicker/RepoBranchPicker'; +import { RepoBranchPickerSchema } from '../components/fields/RepoBranchPicker/schema'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ { diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index 6f4e28c9b0..c6c858f6b1 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -73,8 +73,8 @@ import { MyGroupsPicker, MyGroupsPickerSchema, } from './components/fields/MyGroupsPicker/MyGroupsPicker'; -import { RepoBranchPicker } from './components/fields/BitbucketRepoBranchPicker/RepoBranchPicker'; -import { RepoBranchPickerSchema } from './components/fields/BitbucketRepoBranchPicker/schema'; +import { RepoBranchPicker } from './components/fields/RepoBranchPicker/RepoBranchPicker'; +import { RepoBranchPickerSchema } from './components/fields/RepoBranchPicker/schema'; /** * The main plugin export for the scaffolder. From 426bd26366c0f649a36a89f70acd0e97e9da428b Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 18 Jun 2024 15:00:14 +0200 Subject: [PATCH 317/860] test: add tests for listBranchesByRepository to BitbucketCloudClient Signed-off-by: Benjamin Janssens --- .../src/BitbucketCloudClient.test.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts index f625f0daf8..7558c92138 100644 --- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts +++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts @@ -162,4 +162,33 @@ describe('BitbucketCloudClient', () => { expect(results).toHaveLength(1); expect(results[0].slug).toEqual('workspace1'); }); + + it('listBranchesByRepository', async () => { + server.use( + rest.get( + 'https://api.bitbucket.org/2.0/repositories/workspace1/repo1/refs/branches', + (_, res, ctx) => { + const response = { + values: [ + { + type: 'branch', + name: 'branch1', + } as Models.Branch, + ], + }; + return res(ctx.json(response)); + }, + ), + ); + + const pagination = client.listBranchesByRepository('repo1', 'workspace1'); + + const results = []; + for await (const result of pagination.iterateResults()) { + results.push(result); + } + + expect(results).toHaveLength(1); + expect(results[0].name).toEqual('branch1'); + }); }); From 5588a64e80e324ab97cb9647b477cee2793cff49 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Tue, 18 Jun 2024 15:09:46 +0200 Subject: [PATCH 318/860] test: add tests for branches for handleBitbucketCloudRequest Signed-off-by: Benjamin Janssens --- .../src/autocomplete/autocomplete.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts index 0447ff2d28..b124c65f78 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts @@ -35,6 +35,11 @@ describe('handleAutocompleteRequest', () => { .fn() .mockReturnValue([{ values: [{ slug: 'repository1' }] }]), }), + listBranchesByRepository: jest.fn().mockReturnValue({ + iteratePages: jest + .fn() + .mockReturnValue([{ values: [{ name: 'branch1' }] }]), + }), }; const fromConfig = jest @@ -89,6 +94,15 @@ describe('handleAutocompleteRequest', () => { expect(result).toEqual({ results: [{ title: 'repository1' }] }); }); + it('should return branches', async () => { + const result = await handleBitbucketCloudRequest('foo', 'branches', { + workspace: 'workspace1', + repository: 'repository1', + }); + + expect(result).toEqual(['branch1']); + }); + it('should throw an error when passing an invalid resource', async () => { await expect( handleAutocompleteRequest({ From 8329e930c6f7e7f0b3654b2e7af8d098d246527a Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Wed, 19 Jun 2024 09:52:17 +0200 Subject: [PATCH 319/860] test: add tests for RepoBranchPicker Signed-off-by: Benjamin Janssens --- .../RepoBranchPicker.test.tsx | 324 ++++++++++++++++++ .../RepoBranchPicker/RepoBranchPicker.tsx | 5 +- 2 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx new file mode 100644 index 0000000000..eb5ebd1730 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx @@ -0,0 +1,324 @@ +/* + * 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 { Form } from '@backstage/plugin-scaffolder-react/alpha'; +import validator from '@rjsf/validator-ajv8'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { + scmIntegrationsApiRef, + ScmIntegrationsApi, + scmAuthApiRef, + ScmAuthApi, +} from '@backstage/integration-react'; + +import { + SecretsContextProvider, + scaffolderApiRef, + useTemplateSecrets, + ScaffolderRJSFField, +} from '@backstage/plugin-scaffolder-react'; +import { act, fireEvent } from '@testing-library/react'; +import { RepoBranchPicker } from './RepoBranchPicker'; + +describe('RepoBranchPicker', () => { + const mockIntegrationsApi: Partial = { + byHost: () => ({ type: 'bitbucket' }), + }; + + let mockScmAuthApi: Partial; + + beforeEach(() => { + mockScmAuthApi = { + getCredentials: jest.fn().mockResolvedValue({ token: 'abc123' }), + }; + }); + + describe('happy path rendering', () => { + it('should render the repo branch picker with minimal props', async () => { + const onSubmit = jest.fn(); + + const { getByRole } = await renderInTestApp( + + +
    , + }} + onSubmit={onSubmit} + formContext={{ + formData: { + repoUrl: 'bitbucket.org', + }, + }} + /> + + , + ); + + const input = getByRole('textbox'); + const submitButton = getByRole('button'); + + act(() => { + input.focus(); + fireEvent.change(input, { target: { value: 'branch1' } }); + input.blur(); + }); + + fireEvent.click(submitButton); + + expect(onSubmit).toHaveBeenCalledWith( + expect.objectContaining({ + formData: 'branch1', + }), + expect.anything(), + ); + }); + + it('should render properly with title and description', async () => { + const { getByText } = await renderInTestApp( + + + , + }} + formContext={{ + formData: { + repoUrl: 'bitbucket.org', + }, + }} + /> + + , + ); + + expect(getByText('test title')).toBeInTheDocument(); + expect(getByText('test description')).toBeInTheDocument(); + }); + }); + + describe('requestUserCredentials', () => { + it('should call the scmAuthApi with the correct params', async () => { + const SecretsComponent = () => { + const { secrets } = useTemplateSecrets(); + return ( +
    {JSON.stringify({ secrets })}
    + ); + }; + const { getByTestId } = await renderInTestApp( + + + , + }} + formContext={{ + formData: { + repoUrl: 'github.com', + }, + }} + /> + + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: 'https://github.com', + additionalScope: { + repoWrite: true, + customScopes: { + github: ['workflow'], + }, + }, + }); + + const currentSecrets = JSON.parse( + getByTestId('current-secrets').textContent!, + ); + + expect(currentSecrets).toEqual({ + secrets: { testKey: 'abc123' }, + }); + }); + + 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( + + + , + }} + formContext={{ + formData: { + repoUrl: 'gitlab.example.com', + }, + }} + /> + + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: 'https://gitlab.example.com', + additionalScope: { + repoWrite: true, + }, + }); + }); + + it('should not call the scmAuthApi if secret is available in the state', async () => { + const SecretsComponent = () => { + const { secrets } = useTemplateSecrets(); + return ( +
    {JSON.stringify({ secrets })}
    + ); + }; + const { getByTestId } = await renderInTestApp( + + + , + }} + formContext={{ + formData: { + repoUrl: 'github.com', + }, + }} + /> + + + , + ); + + await act(async () => { + // 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( + getByTestId('current-secrets').textContent!, + ); + + expect(currentSecrets).toEqual({ + secrets: { testKey: 'abc123' }, + }); + }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx index 2ba1eddbfc..8ab83bd717 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx @@ -20,8 +20,6 @@ import { scmAuthApiRef, } from '@backstage/integration-react'; import React, { useEffect, useState, useCallback } from 'react'; -import { RepoBranchPickerProps } from './schema'; -import { RepoBranchPickerState } from './types'; import useDebounce from 'react-use/esm/useDebounce'; import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react'; import Box from '@material-ui/core/Box'; @@ -29,6 +27,9 @@ import Divider from '@material-ui/core/Divider'; import Typography from '@material-ui/core/Typography'; import { BitbucketRepoBranchPicker } from './BitbucketRepoBranchPicker'; +import { RepoBranchPickerProps } from './schema'; +import { RepoBranchPickerState } from './types'; + /** * The underlying component that is rendered in the form for the `RepoBranchPicker` * field extension. From 80738256c37e4ace961dbf31fe0e02b04371075d Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Wed, 19 Jun 2024 13:48:49 +0200 Subject: [PATCH 320/860] chore: copy comments from RepoUrlPicker to stay consistent Signed-off-by: Benjamin Janssens --- .../fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx | 7 +++++++ .../src/components/fields/RepoBranchPicker/schema.ts | 3 +++ 2 files changed, 10 insertions(+) diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx index 3af7eb7e2c..23e8f01617 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -24,6 +24,13 @@ import { useApi } from '@backstage/core-plugin-api'; import { RepoBranchPickerState } from './types'; import FormHelperText from '@material-ui/core/FormHelperText'; +/** + * The underlying component that is rendered in the form for the `BitbucketRepoBranchPicker` + * field extension. + * + * @public + * + */ export const BitbucketRepoBranchPicker = ({ onChange, state, diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/schema.ts b/plugins/scaffolder/src/components/fields/RepoBranchPicker/schema.ts index 12ed07fd80..6ee67bd1c7 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/schema.ts +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/schema.ts @@ -77,4 +77,7 @@ export type RepoBranchPickerUiOptions = export type RepoBranchPickerProps = typeof RepoBranchPickerFieldSchema.type; +// NOTE: There is a bug with this failing validation in the custom field explorer due +// to https://github.com/rjsf-team/react-jsonschema-form/issues/675 even if +// requestUserCredentials is not defined export const RepoBranchPickerSchema = RepoBranchPickerFieldSchema.schema; From 37d52e4f2830ff15af55a60bfd5d8afd7ea36c2b Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Wed, 19 Jun 2024 16:37:33 +0200 Subject: [PATCH 321/860] feat: fall back on DefaultRepoBranchPicker if host is not bitbucket Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.tsx | 6 +- .../DefaultRepoBranchPicker.test.tsx | 55 +++++++++++++++++ .../DefaultRepoBranchPicker.tsx | 60 +++++++++++++++++++ .../RepoBranchPicker.test.tsx | 10 +--- .../RepoBranchPicker/RepoBranchPicker.tsx | 53 +++++++++++----- 5 files changed, 160 insertions(+), 24 deletions(-) create mode 100644 plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.test.tsx create mode 100644 plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx index 23e8f01617..76de25dba0 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -36,11 +36,13 @@ export const BitbucketRepoBranchPicker = ({ state, rawErrors, accessToken, + required, }: { onChange: (state: RepoBranchPickerState) => void; state: RepoBranchPickerState; rawErrors: string[]; accessToken?: string; + required?: boolean; }) => { const { host, workspace, repository, branch } = state; @@ -79,7 +81,7 @@ export const BitbucketRepoBranchPicker = ({ return ( 0 && !branch} > ( - + )} freeSolo autoSelect diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.test.tsx new file mode 100644 index 0000000000..77589e4478 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.test.tsx @@ -0,0 +1,55 @@ +/* + * 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 { fireEvent, render } from '@testing-library/react'; + +import { DefaultRepoBranchPicker } from './DefaultRepoBranchPicker'; + +describe('DefaultRepoBranchPicker', () => { + it('renders an input field', () => { + const { getByRole } = render( + , + ); + + expect(getByRole('textbox')).toBeInTheDocument(); + expect(getByRole('textbox')).toHaveValue('main'); + }); + + it('calls onChange when the input field changes', () => { + const onChange = jest.fn(); + + const { getByRole } = render( + , + ); + + const input = getByRole('textbox'); + + fireEvent.change(input, { + target: { value: 'develop' }, + }); + + expect(onChange).toHaveBeenCalledWith({ branch: 'develop' }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx new file mode 100644 index 0000000000..52a4a15e23 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx @@ -0,0 +1,60 @@ +/* + * 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 FormControl from '@material-ui/core/FormControl'; +import React from 'react'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import Input from '@material-ui/core/Input'; +import InputLabel from '@material-ui/core/InputLabel'; + +import { RepoBranchPickerState } from './types'; + +/** + * The underlying component that is rendered in the form for the `DefaultRepoBranchPicker` + * field extension. + * + * @public + * + */ +export const DefaultRepoBranchPicker = ({ + onChange, + state, + rawErrors, + required, +}: { + onChange: (state: RepoBranchPickerState) => void; + state: RepoBranchPickerState; + rawErrors: string[]; + required?: boolean; +}) => { + const { branch } = state; + + return ( + 0 && !branch} + > + Branch + onChange({ branch: e.target.value })} + value={branch} + /> + The branch of the repository + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx index eb5ebd1730..ece73670f6 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx @@ -70,9 +70,7 @@ describe('RepoBranchPicker', () => { }} onSubmit={onSubmit} formContext={{ - formData: { - repoUrl: 'bitbucket.org', - }, + formData: {}, }} /> @@ -82,11 +80,7 @@ describe('RepoBranchPicker', () => { const input = getByRole('textbox'); const submitButton = getByRole('button'); - act(() => { - input.focus(); - fireEvent.change(input, { target: { value: 'branch1' } }); - input.blur(); - }); + fireEvent.change(input, { target: { value: 'branch1' } }); fireEvent.click(submitButton); diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx index 8ab83bd717..4ca22c8f80 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.tsx @@ -25,10 +25,11 @@ import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react'; import Box from '@material-ui/core/Box'; import Divider from '@material-ui/core/Divider'; import Typography from '@material-ui/core/Typography'; -import { BitbucketRepoBranchPicker } from './BitbucketRepoBranchPicker'; import { RepoBranchPickerProps } from './schema'; import { RepoBranchPickerState } from './types'; +import { BitbucketRepoBranchPicker } from './BitbucketRepoBranchPicker'; +import { DefaultRepoBranchPicker } from './DefaultRepoBranchPicker'; /** * The underlying component that is rendered in the form for the `RepoBranchPicker` @@ -37,8 +38,15 @@ import { RepoBranchPickerState } from './types'; * @public */ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { - const { uiSchema, onChange, rawErrors, formData, schema, formContext } = - props; + const { + uiSchema, + onChange, + rawErrors, + formData, + schema, + formContext, + required, + } = props; const { formData: { repoUrl }, } = formContext; @@ -111,6 +119,33 @@ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { const hostType = (host && integrationApi.byHost(host)?.type) ?? null; + const renderRepoBranchPicker = () => { + switch (hostType) { + case 'bitbucket': + return ( + + ); + default: + return ( + + ); + } + }; + return ( <> {schema.title && ( @@ -122,17 +157,7 @@ export const RepoBranchPicker = (props: RepoBranchPickerProps) => { {schema.description && ( {schema.description} )} - {hostType === 'bitbucket' && ( - - )} + {renderRepoBranchPicker()} ); }; From 7d82969f10086d0d062af813476df906b278e438 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 28 Jun 2024 11:56:51 +0200 Subject: [PATCH 322/860] chore: update BitbucketRepoBranchPicker and handleAutocompleteRequest Signed-off-by: Benjamin Janssens --- .../src/autocomplete/autocomplete.test.ts | 12 ++++++++---- .../src/autocomplete/autocomplete.ts | 8 ++++---- .../BitbucketRepoBranchPicker.test.tsx | 4 +++- .../BitbucketRepoBranchPicker.tsx | 17 +++++++++-------- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts index b124c65f78..d99a8358b9 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts @@ -95,12 +95,16 @@ describe('handleAutocompleteRequest', () => { }); it('should return branches', async () => { - const result = await handleBitbucketCloudRequest('foo', 'branches', { - workspace: 'workspace1', - repository: 'repository1', + const result = await handleAutocompleteRequest({ + token: 'foo', + resource: 'branches', + context: { + workspace: 'workspace1', + repository: 'repository1', + }, }); - expect(result).toEqual(['branch1']); + expect(result).toEqual({ results: [{ title: 'branch1' }] }); }); it('should throw an error when passing an invalid resource', async () => { diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts index 70824995ac..58d2bc9c6d 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts @@ -78,21 +78,21 @@ export async function handleAutocompleteRequest({ return { results: result.map(title => ({ title })) }; } case 'branches': { - if (!parameters.workspace || !parameters.repository) + if (!context.workspace || !context.repository) throw new InputError( - 'Missing workspace and/or repository query parameter', + 'Missing workspace and/or repository context parameter', ); const result: string[] = []; for await (const page of client - .listBranchesByRepository(parameters.repository, parameters.workspace) + .listBranchesByRepository(context.repository, context.workspace) .iteratePages()) { const names = [...page.values!].map(p => p.name!); result.push(...names); } - return result; + return { results: result.map(title => ({ title })) }; } default: throw new InputError(`Invalid resource: ${resource}`); diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.test.tsx index 6cbc561bc9..638a05b4ce 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.test.tsx @@ -26,7 +26,9 @@ import userEvent from '@testing-library/user-event'; describe('BitbucketRepoBranchPicker', () => { const scaffolderApiMock: Partial = { - autocomplete: jest.fn().mockResolvedValue(['branch1']), + autocomplete: jest + .fn() + .mockResolvedValue({ results: [{ title: 'branch1' }] }), }; it('renders an input field', () => { diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx index 76de25dba0..ed54cddc5e 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -57,16 +57,17 @@ export const BitbucketRepoBranchPicker = ({ host === 'bitbucket.org' && accessToken && workspace && - repository + repository && + scaffolderApi.autocomplete ) { - const result = await scaffolderApi.autocomplete( - accessToken, - 'bitbucketCloud', - 'branches', - { workspace, repository }, - ); + const { results } = await scaffolderApi.autocomplete({ + token: accessToken, + resource: 'branches', + context: { workspace, repository }, + provider: 'bitbucket-cloud', + }); - setAvailableBranches(result); + setAvailableBranches(results.map(r => r.title)); } else { setAvailableBranches([]); } From caf7fc23c3f172a9744b9bbf72ff9a92f8094e10 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 28 Jun 2024 13:16:50 +0200 Subject: [PATCH 323/860] docs: extend documentation Signed-off-by: Benjamin Janssens --- .../software-templates/ui-options-examples.md | 27 ++++++++++++++++++ .../software-templates/writing-templates.md | 28 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/docs/features/software-templates/ui-options-examples.md b/docs/features/software-templates/ui-options-examples.md index 7f0e5b225f..1a024569a6 100644 --- a/docs/features/software-templates/ui-options-examples.md +++ b/docs/features/software-templates/ui-options-examples.md @@ -441,3 +441,30 @@ repoUrl: `secretsKey` is the key used within the template secrets context to store the credential and `additionalScopes` is any additional permission scopes to request. The supported `additionalScopes` values are `gerrit`, `github`, `gitlab`, `bitbucket`, and `azure`. + +## RepoBranchPicker + +The input props that can be specified under `ui:options` for the `RepoBranchPicker` field extension. + +### `requestUserCredentials` + +If defined will request user credentials to auth against the given SCM platform. + +```yaml +repoUrl: + title: Repository Branch + type: string + ui:field: RepoBranchPicker + ui:options: + requestUserCredentials: + secretsKey: USER_OAUTH_TOKEN + additionalScopes: + github: + - workflow:write +``` + +`secretsKey` is the key used within the template secrets context to store the credential and `additionalScopes` is any additional permission scopes to request. + +The supported `additionalScopes` values are `gerrit`, `github`, `gitlab`, `bitbucket`, and `azure`. + +If you're also using the `RepoUrlPicker` field extension, you should simply duplicate this part from there. diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 15591eeb67..12bf65765a 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -477,6 +477,34 @@ template can be published to multiple providers. Note, that you will need to configure an [authentication provider](../../auth/index.md#configuring-authentication-providers), alongside the [`ScmAuthApi`](../../auth/index.md#scaffolder-configuration-software-templates) for your source code management (SCM) service to make this feature work. +### The Repository Branch Picker + +Similar to the repository picker, there is a picker for branches to support autocompletion. A full example could look like this: + +```yaml +- title: Choose a branch + required: + - repoBranch + properties: + repoBranch: + title: Repository Branch + type: string + ui:field: RepoBranchPicker + ui:options: + requestUserCredentials: + secretsKey: USER_OAUTH_TOKEN +``` + +Passing the `requestUserCredentials` object is required for autocompletion to work. +If you're also using the repository picker, you should simply duplicate this part from there. +For more information regarding the `requestUserCredentials` object, please refer to the [Using the Users `oauth` token](#using-the-users-oauth-token) section under [The Repository Picker](#the-repository-picker). + +For a list of all possible `ui:options` input props for `RepoBranchPicker`, please visit [here](./ui-options-examples.md#repobranchpicker). + +The `RepoBranchPicker` is a custom field that we provide part of the +`plugin-scaffolder`. You can provide your own custom fields by +[writing your own Custom Field Extensions](./writing-custom-field-extensions.md) + ### Accessing the signed-in users details Sometimes when authoring templates, you'll want to access the user that is running the template, and get details from the profile or the users `Entity` in the Catalog. From 3fca64320d18d8093557ccc666a3c3769b8d9535 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 28 Jun 2024 13:24:57 +0200 Subject: [PATCH 324/860] chore: add changesets Signed-off-by: Benjamin Janssens --- .changeset/fast-bulldogs-relax.md | 5 +++++ .changeset/tough-goats-hang.md | 5 +++++ .changeset/witty-timers-marry.md | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 .changeset/fast-bulldogs-relax.md create mode 100644 .changeset/tough-goats-hang.md create mode 100644 .changeset/witty-timers-marry.md diff --git a/.changeset/fast-bulldogs-relax.md b/.changeset/fast-bulldogs-relax.md new file mode 100644 index 0000000000..65895345e9 --- /dev/null +++ b/.changeset/fast-bulldogs-relax.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch +--- + +Added autocompletion support for resource `branches` diff --git a/.changeset/tough-goats-hang.md b/.changeset/tough-goats-hang.md new file mode 100644 index 0000000000..6090c582d0 --- /dev/null +++ b/.changeset/tough-goats-hang.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Added field extension `RepoBranchPicker` diff --git a/.changeset/witty-timers-marry.md b/.changeset/witty-timers-marry.md new file mode 100644 index 0000000000..4193acb6fc --- /dev/null +++ b/.changeset/witty-timers-marry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-bitbucket-cloud-common': patch +--- + +Added method `listBranchesByRepository` to `BitbucketCloudClient` From 1ae05800608f8e39c2b1e4eaec8efeeff724ff5c Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 28 Jun 2024 13:26:31 +0200 Subject: [PATCH 325/860] chore: update API reports Signed-off-by: Benjamin Janssens --- plugins/bitbucket-cloud-common/api-report.md | 9 ++++++++ plugins/scaffolder/api-report.md | 22 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/plugins/bitbucket-cloud-common/api-report.md b/plugins/bitbucket-cloud-common/api-report.md index 34c245facc..833a367c03 100644 --- a/plugins/bitbucket-cloud-common/api-report.md +++ b/plugins/bitbucket-cloud-common/api-report.md @@ -12,6 +12,12 @@ export class BitbucketCloudClient { config: BitbucketCloudIntegrationConfig, ): BitbucketCloudClient; // (undocumented) + listBranchesByRepository( + repository: string, + workspace: string, + options?: FilterAndSortOptions & PartialResponseOptions, + ): WithPagination; + // (undocumented) listProjectsByWorkspace( workspace: string, options?: FilterAndSortOptions & PartialResponseOptions, @@ -209,6 +215,9 @@ export namespace Models { size?: number; values?: Array | Set; } + export interface PaginatedBranches extends Paginated { + values?: Set; + } export interface PaginatedProjects extends Paginated { values?: Set; } diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index f479b13ec4..6641cda26b 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -384,6 +384,28 @@ export const OwnerPickerFieldSchema: FieldSchema< // @public export type OwnerPickerUiOptions = typeof OwnerPickerFieldSchema.uiOptionsType; +// @public +export const RepoBranchPickerFieldExtension: FieldExtensionComponent_2< + string, + { + requestUserCredentials?: + | { + secretsKey: string; + additionalScopes?: + | { + azure?: string[] | undefined; + github?: string[] | undefined; + gitlab?: string[] | undefined; + bitbucket?: string[] | undefined; + gerrit?: string[] | undefined; + gitea?: string[] | undefined; + } + | undefined; + } + | undefined; + } +>; + // @public export const repoPickerValidation: ( value: string, From c59167016378de2b5206737ab283b43d5b77887a Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Wed, 26 Jun 2024 16:07:06 -0600 Subject: [PATCH 326/860] 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 327/860] 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 328/860] 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 329/860] 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 330/860] 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 331/860] 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 332/860] 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 333/860] 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 334/860] 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 335/860] 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 336/860] 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 337/860] 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 338/860] 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 339/860] 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 340/860] 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 341/860] 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 342/860] 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 343/860] 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 344/860] 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 345/860] 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 346/860] 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 347/860] 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 348/860] 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 349/860] 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 350/860] 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 351/860] 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 352/860] 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 353/860] 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 354/860] 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 355/860] 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 356/860] 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 357/860] 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 358/860] 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 359/860] 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 360/860] 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 361/860] 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 362/860] 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 363/860] 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 364/860] 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 365/860] 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 366/860] 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 367/860] 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 368/860] 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 362ae34cb4b9a87a8a3e41f5a7c94bcbee7eb346 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 4 Jul 2024 13:53:18 +0200 Subject: [PATCH 369/860] refactor: extract BaseRepoBranchPickerProps Signed-off-by: Benjamin Janssens --- .../RepoBranchPicker/BitbucketRepoBranchPicker.tsx | 10 +++------- .../RepoBranchPicker/DefaultRepoBranchPicker.tsx | 9 ++------- .../src/components/fields/RepoBranchPicker/types.ts | 7 +++++++ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx index ed54cddc5e..f6e6634ed8 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -21,7 +21,7 @@ import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; import useDebounce from 'react-use/esm/useDebounce'; import { useApi } from '@backstage/core-plugin-api'; -import { RepoBranchPickerState } from './types'; +import { BaseRepoBranchPickerProps } from './types'; import FormHelperText from '@material-ui/core/FormHelperText'; /** @@ -37,13 +37,9 @@ export const BitbucketRepoBranchPicker = ({ rawErrors, accessToken, required, -}: { - onChange: (state: RepoBranchPickerState) => void; - state: RepoBranchPickerState; - rawErrors: string[]; +}: BaseRepoBranchPickerProps<{ accessToken?: string; - required?: boolean; -}) => { +}>) => { const { host, workspace, repository, branch } = state; const [availableBranches, setAvailableBranches] = useState([]); diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx index 52a4a15e23..9350e232f8 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.tsx @@ -20,7 +20,7 @@ import FormHelperText from '@material-ui/core/FormHelperText'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; -import { RepoBranchPickerState } from './types'; +import { BaseRepoBranchPickerProps } from './types'; /** * The underlying component that is rendered in the form for the `DefaultRepoBranchPicker` @@ -34,12 +34,7 @@ export const DefaultRepoBranchPicker = ({ state, rawErrors, required, -}: { - onChange: (state: RepoBranchPickerState) => void; - state: RepoBranchPickerState; - rawErrors: string[]; - required?: boolean; -}) => { +}: BaseRepoBranchPickerProps) => { const { branch } = state; return ( diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/types.ts b/plugins/scaffolder/src/components/fields/RepoBranchPicker/types.ts index 1d54ea7e8b..bd218d9e28 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/types.ts +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/types.ts @@ -20,3 +20,10 @@ export interface RepoBranchPickerState { repository?: string; branch?: string; } + +export type BaseRepoBranchPickerProps = T & { + onChange: (state: RepoBranchPickerState) => void; + state: RepoBranchPickerState; + rawErrors: string[]; + required?: boolean; +}; From 3cea09fcf2c9cb8a990ff7ddd9be42174e8958c6 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 4 Jul 2024 14:09:27 +0200 Subject: [PATCH 370/860] chore: remove unnecessary mapping from handleAutocompleteRequest Signed-off-by: Benjamin Janssens --- .../src/autocomplete/autocomplete.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts index 58d2bc9c6d..75cc170a30 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts @@ -34,29 +34,29 @@ export async function handleAutocompleteRequest({ switch (resource) { case 'workspaces': { - const result: string[] = []; + const results: { title: string }[] = []; for await (const page of client.listWorkspaces().iteratePages()) { - const slugs = [...page.values!].map(p => p.slug!); - result.push(...slugs); + const slugs = [...page.values!].map(p => ({ title: p.slug! })); + results.push(...slugs); } - return { results: result.map(title => ({ title })) }; + return { results }; } case 'projects': { if (!context.workspace) throw new InputError('Missing workspace context parameter'); - const result: string[] = []; + const results: { title: string }[] = []; for await (const page of client .listProjectsByWorkspace(context.workspace) .iteratePages()) { - const keys = [...page.values!].map(p => p.key!); - result.push(...keys); + const keys = [...page.values!].map(p => ({ title: p.key! })); + results.push(...keys); } - return { results: result.map(title => ({ title })) }; + return { results }; } case 'repositories': { if (!context.workspace || !context.project) @@ -64,18 +64,18 @@ export async function handleAutocompleteRequest({ 'Missing workspace and/or project context parameter', ); - const result: string[] = []; + const results: { title: string }[] = []; for await (const page of client .listRepositoriesByWorkspace(context.workspace, { q: `project.key="${context.project}"`, }) .iteratePages()) { - const slugs = [...page.values!].map(p => p.slug!); - result.push(...slugs); + const slugs = [...page.values!].map(p => ({ title: p.slug! })); + results.push(...slugs); } - return { results: result.map(title => ({ title })) }; + return { results }; } case 'branches': { if (!context.workspace || !context.repository) @@ -83,16 +83,16 @@ export async function handleAutocompleteRequest({ 'Missing workspace and/or repository context parameter', ); - const result: string[] = []; + const results: { title: string }[] = []; for await (const page of client .listBranchesByRepository(context.repository, context.workspace) .iteratePages()) { - const names = [...page.values!].map(p => p.name!); - result.push(...names); + const names = [...page.values!].map(p => ({ title: p.name! })); + results.push(...names); } - return { results: result.map(title => ({ title })) }; + return { results }; } default: throw new InputError(`Invalid resource: ${resource}`); From 618aa1454890c9c2c499f3a2c178993978308a95 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 4 Jul 2024 14:14:20 +0200 Subject: [PATCH 371/860] refactor: use useCallback for updateAvailableBranches Co-authored-by: Camila Belo Signed-off-by: Benjamin Janssens --- .../BitbucketRepoBranchPicker.tsx | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx index f6e6634ed8..76b8d071ea 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -46,34 +46,34 @@ export const BitbucketRepoBranchPicker = ({ const scaffolderApi = useApi(scaffolderApiRef); - useDebounce( - () => { - const updateAvailableBranches = async () => { - if ( - host === 'bitbucket.org' && - accessToken && - workspace && - repository && - scaffolderApi.autocomplete - ) { - const { results } = await scaffolderApi.autocomplete({ - token: accessToken, - resource: 'branches', - context: { workspace, repository }, - provider: 'bitbucket-cloud', - }); + const updateAvailableBranches = useCallback(() => { + if ( + !scaffolderApi.autocomplete || + !workspace || + !repository || + !accessToken || + host !== 'bitbucket.org' + ) { + setAvailableBranches([]); + return; + } - setAvailableBranches(results.map(r => r.title)); - } else { - setAvailableBranches([]); - } - }; + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'branches', + context: { workspace, repository }, + provider: 'bitbucket-cloud', + }) + .then(({ results }) => { + setAvailableBranches(results.map(r => r.title)); + }) + .catch(() => { + setAvailableBranches([]); + }); + }, [host, workspace, repository, accessToken, scaffolderApi]); - updateAvailableBranches().catch(() => setAvailableBranches([])); - }, - 500, - [host, workspace, repository, accessToken], - ); + useDebounce(updateAvailableBranches, 500, [updateAvailableBranches]); return ( Date: Thu, 4 Jul 2024 16:08:13 +0200 Subject: [PATCH 372/860] test: simplify checking for the secret in the document; remove SecretsComponent from test that didn't use it Signed-off-by: Benjamin Janssens --- .../RepoBranchPicker.test.tsx | 49 +++++++------------ 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx index ece73670f6..f9c23be407 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/RepoBranchPicker.test.tsx @@ -133,13 +133,15 @@ describe('RepoBranchPicker', () => { 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': 'RepoBranchPicker', 'ui:options': { requestUserCredentials: { - secretsKey: 'testKey', + secretsKey, additionalScopes: { github: ['workflow'] }, }, }, @@ -190,22 +192,10 @@ describe('RepoBranchPicker', () => { }, }); - 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( { }, }} /> - , ); @@ -256,13 +245,15 @@ describe('RepoBranchPicker', () => { }); 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, {}], ]} > - + { 'ui:field': 'RepoBranchPicker', 'ui:options': { requestUserCredentials: { - secretsKey: 'testKey', + secretsKey, additionalScopes: { github: ['workflow'] }, }, }, @@ -306,13 +297,7 @@ describe('RepoBranchPicker', () => { // 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 3956205ad85fb808386edfac1dab7ff273216225 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 4 Jul 2024 16:31:01 +0200 Subject: [PATCH 373/860] fix: import useCallback in BitbucketRepoBranchPicker Signed-off-by: Benjamin Janssens --- .../fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx index 76b8d071ea..26853d6d05 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -16,7 +16,7 @@ import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import FormControl from '@material-ui/core/FormControl'; -import React, { useState } from 'react'; +import React, { useCallback, useState } from 'react'; import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; import useDebounce from 'react-use/esm/useDebounce'; From 031f07d470782a116b7de613173c426ec33703be Mon Sep 17 00:00:00 2001 From: Adem Simsek Date: Thu, 4 Jul 2024 16:50:26 +0200 Subject: [PATCH 374/860] 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 375/860] 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 376/860] 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 377/860] 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 378/860] 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 379/860] 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 380/860] 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 381/860] 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 382/860] 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 383/860] 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 384/860] 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 385/860] 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 386/860] 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 e2d34cfcdcf41900d2351b20dcc370082e2cfb88 Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Mon, 8 Jul 2024 13:04:33 +0200 Subject: [PATCH 387/860] Prioritize user documentation over README (notifications, signals) Selected content of notifications and signals README files has been moved upwards to the user documentation. Signed-off-by: Marek Libra --- docs/notifications/getting-started.md | 80 ++++++++++++++++++++----- plugins/notifications-backend/README.md | 58 ++---------------- plugins/notifications/README.md | 8 ++- 3 files changed, 78 insertions(+), 68 deletions(-) diff --git a/docs/notifications/getting-started.md b/docs/notifications/getting-started.md index 6a7ea6314e..583be64cc8 100644 --- a/docs/notifications/getting-started.md +++ b/docs/notifications/getting-started.md @@ -51,6 +51,8 @@ All parametrization is done through component properties, such as the `Notificat ![Notifications Page](notificationsPage.png) +In the `packages/app/src/components/Root/Root.tsx`, tweak the [properties](https://backstage.io/docs/reference/plugin-notifications.notificationssidebaritem) of the `` per specific needs. + ## Use New notifications can be sent either by a backend plugin or an external service through the REST API. @@ -134,12 +136,70 @@ notificationsApi.getNotification(yourId); notificationsApi.getNotification(lastSignal.notification_id); ``` +### Extending Notifications via Processors + +The notifications can be extended with `NotificationProcessor`. These processors allow to decorate notifications before they are sent or/and send the notifications to external services. + +Depending on the needs, a processor can modify the content of a notification or route it to different systems like email, Slack, or other services. + +A good example of how to write a processor is the [Email Processor](https://github.com/backstage/backstage/tree/master/plugins/notifications-backend-module-email). + +Start off by creating a notification processor: + +```ts +import { Notification } from '@backstage/plugin-notifications-common'; +import { NotificationProcessor } from '@backstage/plugin-notifications-node'; + +class MyNotificationProcessor implements NotificationProcessor { + async decorate(notification: Notification): Promise { + if (notification.origin === 'plugin-my-plugin') { + notification.payload.icon = 'my-icon'; + } + return notification; + } + + async send(notification: Notification): Promise { + nodemailer.sendEmail({ + from: 'backstage', + to: 'user', + subject: notification.payload.title, + text: notification.payload.description, + }); + } +} +``` + +Both of the processing functions are optional, and you can implement only one of them. + +Add the notification processor to the notification system by: + +```ts +import { notificationsProcessingExtensionPoint } from '@backstage/plugin-notifications-node'; +import { Notification } from '@backstage/plugin-notifications-common'; + +export const myPlugin = createBackendPlugin({ + pluginId: 'myPlugin', + register(env) { + env.registerInit({ + deps: { + notifications: notificationsProcessingExtensionPoint, + // ... + }, + async init({ notifications }) { + // ... + notifications.addProcessor(new MyNotificationProcessor()); + }, + }); + }, +}); +``` + ### External Services When the emitter of a notification is a Backstage backend plugin, it is mandatory to use the integration via `@backstage/plugin-notifications-node` as described above. If the emitter is a service external to Backstage, an HTTP POST request can be issued directly to the API, assuming that authentication is properly configured. -Refer to the service-to-service auth documentation for more details, focusing on the Static Tokens section for the simplest setup option. +Refer to the [service-to-service auth documentation](https://backstage.io/docs/auth/service-to-service-auth) for more details, focusing on the Static Tokens section for the simplest setup option. An example request for creating a broadcast notification might look like: @@ -149,20 +209,12 @@ curl -X POST https://[BACKSTAGE_BACKEND]/api/notifications -H "Content-Type: app ## Additional info -Up-to-date documentation can be found in the plugins' README files: +Additional details can be found in the plugins' implementation: -- https://github.com/backstage/backstage/blob/master/plugins/notifications/README.md +- https://github.com/backstage/backstage/blob/master/plugins/notifications -- https://github.com/backstage/backstage/blob/master/plugins/notifications-backend/README.md +- https://github.com/backstage/backstage/blob/master/plugins/notifications-backend -- https://github.com/backstage/backstage/blob/master/plugins/notifications-node/README.md +- https://github.com/backstage/backstage/blob/master/plugins/notifications-node -- https://github.com/backstage/backstage/blob/master/plugins/signals-react/README.md - -## Processors - -The default backend behavior when emitting a new notification can be tweaked using processors. - -Depending on the needs, a processor can modify the content of a notification or route it to different systems like email, Slack, or other services. - -A good example of how to write a processor is the [Email Processor](https://github.com/backstage/backstage/tree/master/plugins/notifications-backend-module-email). +- https://github.com/backstage/backstage/blob/master/plugins/signals-react diff --git a/plugins/notifications-backend/README.md b/plugins/notifications-backend/README.md index 60c9a4e078..ebd129f572 100644 --- a/plugins/notifications-backend/README.md +++ b/plugins/notifications-backend/README.md @@ -4,6 +4,10 @@ Welcome to the notifications backend plugin! ## Getting started +```bash +yarn workspace backend add @backstage/notifications-backend +``` + Add the notifications to your backend: ```ts @@ -18,58 +22,8 @@ the signals plugin (`@backstage/plugin-signals-node`, `@backstage/plugin-signals ## Extending Notifications -The notifications can be extended with `NotificationProcessor`. These processors allow to decorate notifications -before they are sent or/and send the notifications to external services. - -Start off by creating a notification processor: - -```ts -import { Notification } from '@backstage/plugin-notifications-common'; -import { NotificationProcessor } from '@backstage/plugin-notifications-node'; - -class MyNotificationProcessor implements NotificationProcessor { - async decorate(notification: Notification): Promise { - if (notification.origin === 'plugin-my-plugin') { - notification.payload.icon = 'my-icon'; - } - return notification; - } - - async send(notification: Notification): Promise { - nodemailer.sendEmail({ - from: 'backstage', - to: 'user', - subject: notification.payload.title, - text: notification.payload.description, - }); - } -} -``` - -Both of the processing functions are optional, and you can implement only one of them. - -Add the notification processor to the notification system by: - -```ts -import { notificationsProcessingExtensionPoint } from '@backstage/plugin-notifications-node'; -import { Notification } from '@backstage/plugin-notifications-common'; - -export const myPlugin = createBackendPlugin({ - pluginId: 'myPlugin', - register(env) { - env.registerInit({ - deps: { - notifications: notificationsProcessingExtensionPoint, - // ... - }, - async init({ notifications }) { - // ... - notifications.addProcessor(new MyNotificationProcessor()); - }, - }); - }, -}); -``` +When a notification is created, it's processing can be customized via `processors`. +Please refer [Backstage documentation](https://backstage.io/docs/notifications) for further details. ## Sending Notifications By Backend Plugins diff --git a/plugins/notifications/README.md b/plugins/notifications/README.md index 63212d2c16..32fbb8c701 100644 --- a/plugins/notifications/README.md +++ b/plugins/notifications/README.md @@ -2,13 +2,17 @@ Welcome to the notifications plugin! -_This plugin was created through the Backstage CLI_ - ## Getting started First, install the `@backstage/plugin-notifications-backend` and `@backstage/plugin-notifications-node` packages. See the documentation for installation instructions. +Then add this frontend package: + +```bash +yarn workspace app add @backstage/notifications +``` + To add the notifications main menu, add the following to your `packages/app/src/components/Root/Root.tsx`: ```tsx From bc2700cbf962e3f3a4554d664a193943224b3f27 Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Mon, 8 Jul 2024 08:26:47 -0500 Subject: [PATCH 388/860] 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 389/860] 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 390/860] 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 391/860] 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 392/860] 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 393/860] 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 394/860] 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 395/860] 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 396/860] 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 397/860] 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 398/860] 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 399/860] 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 400/860] 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 401/860] 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 402/860] 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 403/860] 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 404/860] 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 405/860] 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 406/860] 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 407/860] 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 408/860] 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 409/860] 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 410/860] 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 411/860] 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 412/860] 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 413/860] 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 414/860] 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 415/860] 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 416/860] 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 417/860] Kubernetes react -> Warning: validateDOMNesting(...):