diff --git a/.changeset/angry-dolphins-camp.md b/.changeset/angry-dolphins-camp.md new file mode 100644 index 0000000000..3c598f4a66 --- /dev/null +++ b/.changeset/angry-dolphins-camp.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Add access restrictions to the JWKS external access method config schema diff --git a/.changeset/big-eagles-grab.md b/.changeset/big-eagles-grab.md new file mode 100644 index 0000000000..9ece8f64df --- /dev/null +++ b/.changeset/big-eagles-grab.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Added examples for github:environment:create action and improve its test cases diff --git a/.changeset/blue-pumas-cheer.md b/.changeset/blue-pumas-cheer.md new file mode 100644 index 0000000000..f6cbf180ff --- /dev/null +++ b/.changeset/blue-pumas-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Added the Kubernetes plugin to `create-app` diff --git a/.changeset/breezy-cats-kiss.md b/.changeset/breezy-cats-kiss.md new file mode 100644 index 0000000000..900016c1e8 --- /dev/null +++ b/.changeset/breezy-cats-kiss.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Fixing issue with extension blueprints `inputs` merging. diff --git a/.changeset/breezy-jeans-tie.md b/.changeset/breezy-jeans-tie.md new file mode 100644 index 0000000000..4601389a4c --- /dev/null +++ b/.changeset/breezy-jeans-tie.md @@ -0,0 +1,18 @@ +--- +'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch +'@backstage/plugin-auth-backend-module-vmware-cloud-provider': patch +'@backstage/plugin-auth-backend-module-atlassian-provider': patch +'@backstage/plugin-auth-backend-module-bitbucket-provider': patch +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +'@backstage/plugin-auth-backend-module-onelogin-provider': patch +'@backstage/plugin-auth-backend-module-aws-alb-provider': patch +'@backstage/plugin-auth-backend-module-gcp-iap-provider': patch +'@backstage/plugin-auth-backend-module-github-provider': patch +'@backstage/plugin-auth-backend-module-gitlab-provider': patch +'@backstage/plugin-auth-backend-module-google-provider': patch +'@backstage/plugin-auth-backend-module-oauth2-provider': patch +'@backstage/plugin-auth-backend-module-oidc-provider': patch +'@backstage/plugin-auth-backend-module-okta-provider': patch +--- + +Add `signIn` to authentication provider configuration schema diff --git a/.changeset/breezy-rings-fly.md b/.changeset/breezy-rings-fly.md new file mode 100644 index 0000000000..c3cc1c143d --- /dev/null +++ b/.changeset/breezy-rings-fly.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Fixed a bug in `DefaultTableOutputs` where output elements overlapped on smaller screen sizes diff --git a/.changeset/bright-donkeys-buy.md b/.changeset/bright-donkeys-buy.md new file mode 100644 index 0000000000..ded16ccc2c --- /dev/null +++ b/.changeset/bright-donkeys-buy.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +The entity relation cards available for the new frontend system via `/alpha` now have more accurate and granular default filters. diff --git a/.changeset/bright-fireants-sit.md b/.changeset/bright-fireants-sit.md deleted file mode 100644 index 320bc69ff9..0000000000 --- a/.changeset/bright-fireants-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md deleted file mode 100644 index 35d9c0f869..0000000000 --- a/.changeset/bright-panthers-leave.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch -'@backstage/backend-defaults': patch ---- - -Added a new Root Health Service which adds new endpoints for health checks. diff --git a/.changeset/bright-trainers-brake.md b/.changeset/bright-trainers-brake.md new file mode 100644 index 0000000000..2299d83a32 --- /dev/null +++ b/.changeset/bright-trainers-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Add frontend-dynamic-container role to eslint config factory diff --git a/.changeset/calm-crabs-drop.md b/.changeset/calm-crabs-drop.md new file mode 100644 index 0000000000..09bed7c091 --- /dev/null +++ b/.changeset/calm-crabs-drop.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +Added `createBackendFeatureLoader`, which can be used to create an installable backend feature that can in turn load in additional backend features in a dynamic way. diff --git a/.changeset/calm-jeans-ring.md b/.changeset/calm-jeans-ring.md deleted file mode 100644 index 3d1efcf7bd..0000000000 --- a/.changeset/calm-jeans-ring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -Use virtualization with `EntityPicker` as done earlier with `MultiEntityPicker` to fix performance issues with large data sets. `VirtualizedListbox` extracted into reusable component. diff --git a/.changeset/chatty-adults-boil.md b/.changeset/chatty-adults-boil.md deleted file mode 100644 index 76f3bddf41..0000000000 --- a/.changeset/chatty-adults-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fixed an issue that was causing techdocs pages unnecessarily re-render on navigate. diff --git a/.changeset/chilly-coats-report.md b/.changeset/chilly-coats-report.md deleted file mode 100644 index 2fd044b57c..0000000000 --- a/.changeset/chilly-coats-report.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/backend-test-utils': patch -'@backstage/backend-defaults': patch -'@backstage/backend-app-api': patch ---- - -The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. diff --git a/.changeset/chilly-days-peel.md b/.changeset/chilly-days-peel.md new file mode 100644 index 0000000000..d82344d364 --- /dev/null +++ b/.changeset/chilly-days-peel.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Added support for using the `params` in other properties of the `createExtensionBlueprint` options by providing a callback. diff --git a/.changeset/chilly-rabbits-sneeze.md b/.changeset/chilly-rabbits-sneeze.md deleted file mode 100644 index cbce80ebbc..0000000000 --- a/.changeset/chilly-rabbits-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-atlassian-provider': patch ---- - -Fix several issues with the Atlassian auth provider (type definition, profile url, profile transformation, scopes) diff --git a/.changeset/chilly-roses-trade.md b/.changeset/chilly-roses-trade.md deleted file mode 100644 index 73fc3ff766..0000000000 --- a/.changeset/chilly-roses-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Deprecate legacy status check factory, handler and types. diff --git a/.changeset/chilly-trains-sleep.md b/.changeset/chilly-trains-sleep.md new file mode 100644 index 0000000000..cde7600c8b --- /dev/null +++ b/.changeset/chilly-trains-sleep.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-events-backend-module-aws-sqs': patch +'@backstage/plugin-catalog-backend-module-aws': patch +'@backstage/backend-common': patch +--- + +Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. diff --git a/.changeset/clever-geese-jump.md b/.changeset/clever-geese-jump.md deleted file mode 100644 index 1c4694fa33..0000000000 --- a/.changeset/clever-geese-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer. diff --git a/.changeset/clever-pans-brake.md b/.changeset/clever-pans-brake.md new file mode 100644 index 0000000000..1f49c7a842 --- /dev/null +++ b/.changeset/clever-pans-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-test-utils': patch +--- + +Added new APIs for testing extensions diff --git a/.changeset/clever-waves-judge.md b/.changeset/clever-waves-judge.md deleted file mode 100644 index 100ab66f90..0000000000 --- a/.changeset/clever-waves-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-react': patch ---- - -Resolved the issue where changes in TechDoc add-ons, including the TextSize add-on, were not reapplying during navigation diff --git a/.changeset/cold-jars-punch.md b/.changeset/cold-jars-punch.md deleted file mode 100644 index 8708e1f670..0000000000 --- a/.changeset/cold-jars-punch.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-defaults': minor -'@backstage/backend-app-api': minor ---- - -**BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. diff --git a/.changeset/cool-insects-remember.md b/.changeset/cool-insects-remember.md new file mode 100644 index 0000000000..ab33015377 --- /dev/null +++ b/.changeset/cool-insects-remember.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-notifications': patch +--- + +Add examples for notification:send scaffolder action & improve related tests diff --git a/.changeset/cool-schools-vanish.md b/.changeset/cool-schools-vanish.md new file mode 100644 index 0000000000..9b2ded5248 --- /dev/null +++ b/.changeset/cool-schools-vanish.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fixing loading of additional config files with new `ConfigSources` diff --git a/.changeset/create-app-1719320674.md b/.changeset/create-app-1722413762.md similarity index 100% rename from .changeset/create-app-1719320674.md rename to .changeset/create-app-1722413762.md diff --git a/.changeset/cuddly-zebras-crash.md b/.changeset/cuddly-zebras-crash.md new file mode 100644 index 0000000000..473ac4053f --- /dev/null +++ b/.changeset/cuddly-zebras-crash.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Use ES2022 in CLI bundler diff --git a/.changeset/curvy-pillows-joke.md b/.changeset/curvy-pillows-joke.md new file mode 100644 index 0000000000..25966a51c0 --- /dev/null +++ b/.changeset/curvy-pillows-joke.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Added support for the latest version of `BackendFeature`s from `@backstage/backend-plugin-api`, including feature loaders. diff --git a/.changeset/curvy-teachers-smell.md b/.changeset/curvy-teachers-smell.md deleted file mode 100644 index 3f032f2177..0000000000 --- a/.changeset/curvy-teachers-smell.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch -'@backstage/backend-plugin-api': patch -'@backstage/backend-defaults': patch -'@backstage/backend-tasks': patch ---- - -Fix bug where ISO durations could no longer be used for schedules diff --git a/.changeset/cyan-shrimps-push.md b/.changeset/cyan-shrimps-push.md new file mode 100644 index 0000000000..cb326b4da3 --- /dev/null +++ b/.changeset/cyan-shrimps-push.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Internal updates to support latest version of `BackendFeauture`s from `@backstage/backend-plugin-api`. diff --git a/.changeset/dirty-wasps-do.md b/.changeset/dirty-wasps-do.md deleted file mode 100644 index f8b4e614eb..0000000000 --- a/.changeset/dirty-wasps-do.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Updated `catalog:write` scaffolder action to show correct file path location in log message diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md new file mode 100644 index 0000000000..0a95332eed --- /dev/null +++ b/.changeset/dry-squids-tap.md @@ -0,0 +1,27 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Introduce a new way to encapsulate extension kinds that replaces the extension creator pattern with `createExtensionBlueprint` + +This allows the creation of extension instances with the following pattern: + +```tsx +// create the extension blueprint which is used to create instances +const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', + attachTo: { id: 'test', input: 'default' }, + output: [coreExtensionData.reactElement], + factory(params: { text: string }) { + return [coreExtensionData.reactElement(

{params.text}

)]; + }, +}); + +// create an instance of the extension blueprint with params +const testExtension = EntityCardBlueprint.make({ + name: 'foo', + params: { + text: 'Hello World', + }, +}); +``` diff --git a/.changeset/dull-ghosts-double.md b/.changeset/dull-ghosts-double.md new file mode 100644 index 0000000000..0bc5a09791 --- /dev/null +++ b/.changeset/dull-ghosts-double.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-search-react': patch +'@backstage/plugin-home': patch +--- + +Updated alpha definitions of extension data references. diff --git a/.changeset/early-deers-beg.md b/.changeset/early-deers-beg.md deleted file mode 100644 index 735c68aace..0000000000 --- a/.changeset/early-deers-beg.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`. - -Adding environment secrets now works as expected. diff --git a/.changeset/early-trees-dance.md b/.changeset/early-trees-dance.md new file mode 100644 index 0000000000..55b2c08f89 --- /dev/null +++ b/.changeset/early-trees-dance.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +The `ExtensionBoundary` now by default infers whether it's routable from whether it outputs a route path. diff --git a/.changeset/eighty-emus-leave.md b/.changeset/eighty-emus-leave.md new file mode 100644 index 0000000000..8e02c7cf94 --- /dev/null +++ b/.changeset/eighty-emus-leave.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-techdocs-node': patch +'@backstage/plugin-techdocs': patch +--- + +Use annotation constants from new techdocs-common package. diff --git a/.changeset/eighty-games-wink.md b/.changeset/eighty-games-wink.md deleted file mode 100644 index e87dc56b5f..0000000000 --- a/.changeset/eighty-games-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed bug where `` component with empty string as placeholder gave an error +- 99d672d: Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select". +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.17 + +### Patch Changes + +- 780d994: Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template +- f03d12a: Bumped create-app version. +- e90a2cd: Added the Catalog logs module to the `create-app` template +- 3ac2a6a: Added the Postgres Search Engine to the `create-app` template +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/dev-utils@1.0.35 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @backstage/frontend-app-api@0.7.3 + +### Patch Changes + +- d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets. + + ```yaml + app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false + ``` + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-plugin-api@0.6.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.10 + +### Patch Changes + +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- Updated dependencies + - @backstage/frontend-app-api@0.7.3 + - @backstage/test-utils@1.5.8 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.29 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.13.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/repo-tools@0.9.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/cli-node@0.2.7 + - @backstage/config-loader@1.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.16 + +### Patch Changes + +- c964a3d: Import discovery from backend-defaults instead of backend-common +- Updated dependencies + - @backstage/backend-defaults@0.4.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + +## @backstage/test-utils@1.5.8 + +### Patch Changes + +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + +## @backstage/plugin-api-docs@0.11.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-app-backend@0.3.71 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-app-node@0.1.22 + - @backstage/config-loader@1.8.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-app-node@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/config-loader@1.8.1 + +## @backstage/plugin-app-visualizer@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-auth-backend@0.22.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19 + - @backstage/plugin-auth-backend-module-google-provider@0.1.19 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.3 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.15 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3 + +### Patch Changes + +- b9832ae: Fix several issues with the Atlassian auth provider (type definition, profile url, profile transformation, scopes) +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend@0.22.9 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-auth-node@0.4.17 + +### Patch Changes + +- 55c1a72: Fix issues with Atlassian OAuth provider: retrieve the email and photo that were not in arrays but rather in single props. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-react@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-bitbucket-cloud-common@0.2.21 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/integration@1.13.0 + +## @backstage/plugin-catalog@1.21.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- d133eaa: Added small notes to AboutCard to discourage customizability PRs +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-search-react@1.7.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.17 + +### Patch Changes + +- 4afa050: Export `defaultEksClusterEntityTransformer` to allow library consumers to layer additional changes on top of the default transformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + +## @backstage/plugin-catalog-backend-module-azure@0.1.42 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-tasks@0.5.27 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.36 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-github@0.6.5 + +### Patch Changes + +- 9112efc: Adds support for `repository` events. + + The provider adds a subscription to the topic `github.repository`. + + Hereby, it supports events of type `repository` with actions + + - `archived` + - `deleted` + - `edited` + - `renamed` + - `transferred` + - `unarchived` + + Actions skipped as they don't require entity changes: + + - `created` + - `privatized` + - `publicized` + + If the config option `validateLocationsExist` is enabled, an API request + is necessary and will be executed. + This affects the actions `renamed`, `transferred`, and `unarchive` + of event type `repository`. + + Catalog entities related to the `GithubEntityProvider` instance will be adjusted + according to action and its meaning for them. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend-module-github@0.6.5 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.21 + +### Patch Changes + +- 8db30ad: The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab..restrictUsersToGroup`. Setting this to `true` will make Backstage only import users from the group defined in the `group` key, instead of all users in the organisation (self-hosted) or of the root group (SaaS). It will default to false, keeping the original implementation intact, when not explicitly set. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.21 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-logs@0.0.1 + +### Patch Changes + +- 97caf55: Creates a new module to make logging catalog errors simple. This module subscribes to catalog events and logs them. + + See [Backstage documentation](https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors) for details on how to install + and configure the plugin. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.30 + +### Patch Changes + +- f7bdcea: Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.40 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-common@1.0.25 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-graph@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.12.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-node@1.12.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-react@1.12.2 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- 2030962: Make EntityOwnerPicker display metadata.title or spec.profile.displayName for mode=only-owners instead of metadata.name +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-config-schema@0.1.57 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-devtools-backend@0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/config-loader@1.8.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools-common@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend@0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend-module-azure@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-backend-module-gerrit@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-backend-module-github@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-test-utils@0.1.32 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-node@0.3.8 + +### Patch Changes + +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + +## @backstage/plugin-home@0.7.7 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-home-react@0.1.15 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @backstage/plugin-home-react@0.1.15 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes@0.11.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes-backend@0.18.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-node@0.1.16 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-cluster@0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes-common@0.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.4.1 + +### Patch Changes + +- e3cb6ab: Add a namespace label to RolloutDrawer +- 2414d86: Fix the `HTML` markup of the `FixDialog` component, `ul` and `li` are not allowed inside a `p` tag. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-notifications@0.2.3 + +### Patch Changes + +- 3bf0697: The toolbar on the Notifications page is hidden when there are no listed notifications. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-notifications-backend@0.3.3 + +### Patch Changes + +- d7b8ca5: Added an option to filter notifications by topic +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-notifications-backend-module-email@0.1.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-notifications-common@0.0.5 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/config@1.2.0 + +## @backstage/plugin-notifications-node@0.2.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-org@0.6.27 + +### Patch Changes + +- 5132d28: The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. + +- c307ef4: Added `relationType` property to EntityMembersListCard component that allows for display users related to a group via some other relationship aside from `memberOf`. + + Also, as a side effect, the `relationsType` property has been deprecated in favor of a more accurately named `relationAggregation` property. + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-org-react@0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-permission-backend@0.5.46 + +### Patch Changes + +- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + + - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. + - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + + Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19 + +### Patch Changes + +- ed10fd2: Internal refactor to use new `PolicyQueryUser` type. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-permission-react@0.4.24 + +### Patch Changes + +- 28b2cfb: Improve API Reference documentation +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-proxy-backend@0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.14 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + +### Patch Changes + +- 6a4ad4e: Instead of using hardcoded `targetBranch` now fetch the default branch from Bitbucket repository. + This prevents from errors when no `targetBranch` is provided and the default repository branch is different from `master`, for example: `main`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.46 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- 2fb0eb8: Added support for passing `variables` to `gitlab:pipeline:trigger` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.39 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-node-test-utils@0.1.9 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.4.8 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers +- 0b52438: Serialization of the scaffolder workspace into GCP bucket +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.9 + +### Patch Changes + +- 54429b5: Filename and imports correction for mockActionContext.ts +- Updated dependencies + - @backstage/backend-test-utils@0.4.4 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/types@1.1.1 + +## @backstage/plugin-search@1.4.14 + +### Patch Changes + +- 1117aba: Update deps in search api extension to include fetch api +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/plugin-search-react@1.7.13 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-search-backend@1.5.14 + +### Patch Changes + +- 343f656: The `AuthorizedSearchEngine` will now ignore the deprecated `token` option, and treat it as an unauthorized request. This will not have any effect in practice, since credentials are always provided by the router. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-backend-module-catalog@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-search-backend-module-elasticsearch@1.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + +## @backstage/plugin-search-backend-module-explore@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-pg@0.5.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-techdocs@0.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-node@1.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-search-common@1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-signals@0.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-signals-backend@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-signals-node@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-techdocs@1.10.7 + +### Patch Changes + +- 8fc2622: Fixed an issue that was causing techdocs pages unnecessarily re-render on navigate. +- 6fa652c: Improve default sorting of docs table +- 605b691: Allow for searching TechDocs by entity title +- 60caa92: Fix double scrollbar bug in reader +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-search-react@1.7.13 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.35 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/test-utils@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-search-react@1.7.13 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-techdocs-backend@1.10.9 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/integration@1.13.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/integration-react@1.1.29 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-techdocs-node@1.12.8 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- 4c4d077: Bumps default version of techdocs docker image to latest +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + +## @backstage/plugin-techdocs-react@1.2.6 + +### Patch Changes + +- 8ac9ce5: Resolved the issue where changes in TechDoc add-ons, including the TextSize add-on, were not reapplying during navigation +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-user-settings@0.8.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.99 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-devtools@0.1.16 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## example-app-next@0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-app-visualizer@0.1.8 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## app-next-example-plugin@0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/frontend-plugin-api@0.6.7 + +## example-backend@0.0.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-notifications-backend@0.3.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.8 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5 + - @backstage/plugin-catalog-backend-module-openapi@0.1.40 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/catalog-model@1.5.0 + +## example-backend-legacy@0.2.100 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.39 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-events-backend@0.3.9 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.3 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-pg@0.5.32 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/plugin-signals-node@0.1.8 + - example-app@0.2.99 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## e2e-test@0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.98 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog@1.21.1 + - @backstage/test-utils@1.5.8 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @internal/plugin-todo-list@1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + +## @internal/plugin-todo-list-backend@1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + +## @internal/plugin-todo-list-common@1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 diff --git a/docs/releases/v1.29.0.md b/docs/releases/v1.29.0.md new file mode 100644 index 0000000000..5f7ed1db19 --- /dev/null +++ b/docs/releases/v1.29.0.md @@ -0,0 +1,117 @@ +--- +id: v1.29.0 +title: v1.29.0 +description: Backstage Release v1.29.0 +--- + +These are the release notes for the v1.29.0 release of [Backstage](https://backstage.io/). + +A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done. + +## Highlights + +### BREAKING: Backend System deprecations and removals + +As part of the [work towards a stable 1.0 release of the new backend system](https://github.com/backstage/backstage/issues/24493), there are several new deprecations and breaking changes in the backend system packages: + +**Breaking**: + +- The deprecated `token` option has been removed from `PermissionsService`, and the request options are now required and must contain a `credentials` object. +- The deprecated `getPath` option has been removed from `httpRouterServiceFactory`, the plugin paths are now always `/api/`. +- It is no longer possible to pass service factory callbacks to the `defaultServiceFactories` option of `createSpecializedBackend`. + +**Deprecations**: + +- The ability to define options for service factories through `createServiceFactory` has been deprecated. See the [service architecture documentation](https://backstage.io/docs/backend-system/architecture/services) for more information on how to define customizable services. +- The ability to install backend features in callback form, i.e. `() => BackendFeature`, has been deprecated. This also includes other usages such as `startTestBackend`, and dynamically imported backend features. No manual changes should be needed for this change, as all backend feature creators have been updated to return `BackendFeature` instances directly. +- The `ServiceFactoryTest.get` method has been renamed to `ServiceFactoryTest.getSubject`, and is now deprecated. +- The following types have been renamed to use an `*Options` suffix instead: `ServiceRefConfig`, `RootServiceFactoryConfig`, `PluginServiceFactoryConfig`. +- Deprecated all exports related to the legacy status checker in `@backstage/backend-common`. +- The `isDockerDisabledForTests` function exported by `@backstage/backend-test-utils` has been deprecated. + +### Backend Health Service + +A new health service as been added to the new backend system. This service provides health check endpoints for the backend, and replaces `createStatusCheckRouter` from `@backstage/backend-common`. + +The service helps implement the new `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints, which provide health checks for the entire backend instance. + +You can read more about this new service and how to customize it in the [Root Health Service documentation](https://backstage.io/docs/backend-system/core-services/root-health). + +### New Catalog Logs module + +This new `@backstage/plugin-catalog-backend-module-logs` module is a minimal module that will log any error events that are published by the catalog. This module is useful for making sure that catalog errors are visible in the logs, but you may want to replace it with a more customized solution if the resulting logs are too verbose. + +### Updates to the `@backstage/create-app` template + +New backstage projects created with `@backstage/create-app` will now include the Catalog Logs module for logging catalog error events, as well as support for the Postgres Search Engine. + +### Permission Policy deprecations + +The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + +- `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. +- `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + +Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +### Renaming the `setupRequestMockHandlers` test utility + +The `setupRequestMockHandlers` utility function exported by `@backstage/test-utils` and `@backstage/backend-test-utils` has been renamed to `registerMswTestHooks`. This is done to better reflect the context and the purpose of the function. The old name is deprecated and will be removed in a future release. + +### Catalog GitHub module support for `repository` events + +The GitHub provider module and `GithubEntityProvider` for the Catalog now supports event driven ingestion of repositories by subscribing to `repository` events from GitHub. This includes the actions `archived`, `deleted`, `edited`, `renamed`, `transferred`, and `unarchived`. This is in addition to the existing support for `push` events, which you can read more about in the integration documentation for [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery#events-support). + +Contributed by [@pjungermann](https://github.com/pjungermann) in [#25360](https://github.com/backstage/backstage/pull/25360) + +### Catalog i18n support + +The Catalog plugin as well as the Catalog React library now support internationalization (i18n). This means that you can customize the messaging in the catalog, as well as add translations. You can read more about this in the [i18n documentation](https://backstage.io/docs/plugins/internationalization/). + +Contributed by [@mario-mui](https://github.com/mario-mui) in [#23392](https://github.com/backstage/backstage/pull/23392) + +### Route Binding configuration improvements + +It is now possible to explicitly remove default route bindings, for cases where you don't want a plugin route to be bound to any target at all: + +```yaml +app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false +``` + +### Scaffolder Fields performance improvements + +The `EntityPicker` and `MultiEntityPicker` fields have been updated to improve performance with large catalogs. Contributed by [@kmikko](https://github.com/kmikko) in [#25315](https://github.com/backstage/backstage/pull/25315), [#25380](https://github.com/backstage/backstage/pull/25380) + +### BREAKING: Catalog LDAP Module improvements + +The `@backstage/plugin-catalog-backend-module-ldap` module has been improved to support multiple or no declarations of both user and group configs. + +This change is breaking for `readLdapOrg` and `LdapProviderConfig`, which now both always accept arrays of `users` and `groups` configurations. + +Contributed by [@Jenson3210](https://github.com/Jenson3210) in [#25261](https://github.com/backstage/backstage/pull/25261) + +## Security Fixes + +This release does not contain any security fixes. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.29.0-changelog.md) +- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins) + +Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage. diff --git a/docs/releases/v1.30.0-next.0-changelog.md b/docs/releases/v1.30.0-next.0-changelog.md new file mode 100644 index 0000000000..f3b7f2ef45 --- /dev/null +++ b/docs/releases/v1.30.0-next.0-changelog.md @@ -0,0 +1,2214 @@ +# Release v1.30.0-next.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.30.0-next.0](https://backstage.github.io/upgrade-helper/?to=1.30.0-next.0) + +## @backstage/cli@0.27.0-next.0 + +### Minor Changes + +- 32a38e1: **BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands. + + The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files. + + The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic. + + The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches. + + The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future. + +### Patch Changes + +- 7eb08a6: Add frontend-dynamic-container role to eslint config factory +- fbc7819: Use ES2022 in CLI bundler +- e53074f: Updated default backend plugin to use `RootConfigService` instead of `Config`. This also removes the dependency on `@backstage/config` as it's no longer used. +- ee2b0e5: The experimental module federation build now has the ability to force the use of development versions of `react` and `react-dom` by setting the `FORCE_REACT_DEVELOPMENT` flag. +- 239dffc: Remove usage of deprecated functionality from @backstage/config-loader +- 0eedec3: Add support for dynamic plugins via the EXPERIMENTAL_MODULE_FEDERATION environment variable when running `yarn start`. +- dc4fb4f: Fix for `repo build --all` not properly detecting the experimental public entry point. +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/integration@1.14.0-next.0 + +### Minor Changes + +- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. + +### Patch Changes + +- c591670: Updated functions for `getHarnessEditContentsUrl`, `getHarnessFileContentsUrl`, `getHarnessArchiveUrl`, `getHarnessLatestCommitUrl` and `parseHarnessUrl` to handle account and org level urls +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-react@1.11.0-next.0 + +### Minor Changes + +- 8839381: Add scaffolder option to display object items in separate rows on review page + +### Patch Changes + +- d0e95a7: Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in `FormProps` +- 4670f06: support `ajv-errors` for scaffolder validation to allow for customizing the error messages +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/app-defaults@1.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/backend-app-api@0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/backend-common@0.23.4-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. + +- 7e13b7a: The remaining exports in the package have now been deprecated: + + - `cacheToPluginCacheManager` + - `createLegacyAuthAdapters` + - `LegacyCreateRouter` + - `legacyPlugin` + - `loggerToWinstonLogger` + - `makeLegacyPlugin` + + Users of these export should fully [migrate to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating). + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/backend-defaults@0.4.2-next.0 + +### Patch Changes + +- 4e79d19: The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`. +- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. +- 8e967da: Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/backend-dynamic-feature-service@0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.23-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/backend-openapi-utils@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + +## @backstage/backend-plugin-api@0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/backend-tasks@0.5.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.4.5-next.0 + +### Patch Changes + +- 4e79d19: The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service. +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/config-loader@1.8.2-next.0 + +### Patch Changes + +- 493feac: Add boolean `allowMissingDefaultConfig` option to `ConfigSources.default` and + `ConfigSources.defaultForTargets`, which results in omission of a ConfigSource + for the default app-config.yaml configuration file if it's not present. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.14.1-next.0 + +### Patch Changes + +- 9a46a81: The request to delete the session cookie when running the app in protected mode is now done with a plain `fetch` rather than `FetchApi`. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/core-compat-api@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/core-components@0.14.10-next.0 + +### Patch Changes + +- 678971a: Move the `Link` component to the `RoutedTabs` instead of the `HeaderTabs` component +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.18-next.0 + +### Patch Changes + +- c0a705d: Added the Kubernetes plugin to `create-app` +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/dev-utils@1.0.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + +## @backstage/frontend-app-api@0.7.4-next.0 + +### Patch Changes + +- 7777b5f: Support icon overriding with the new `IconBundleBlueprint` API. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-plugin-api@0.6.8-next.0 + +### Patch Changes + +- 4e53ad6: Introduce a new way to encapsulate extension kinds that replaces the extension creator pattern with `createExtensionBlueprint` + + This allows the creation of extension instances with the following pattern: + + ```tsx + // create the extension blueprint which is used to create instances + const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(params: { text: string }) { + return { + element:

{params.text}

, + }; + }, + }); + + // create an instance of the extension blueprint with params + const testExtension = EntityCardBlueprint.make({ + name: 'foo', + params: { + text: 'Hello World', + }, + }); + ``` + +- 9b89b82: The `ExtensionBoundary` now by default infers whether it's routable from whether it outputs a route path. + +- 7777b5f: Added a new `IconBundleBlueprint` that lets you create icon bundle extensions that can be installed in an App in order to override or add new app icons. + + ```tsx + import { IconBundleBlueprint } from '@backstage/frontend-plugin-api'; + + const exampleIconBundle = IconBundleBlueprint.make({ + name: 'example-bundle', + params: { + icons: { + user: MyOwnUserIcon, + }, + }, + }); + ``` + +- 31bfc44: Extension data references can now be defined in a way that encapsulates the ID string in the type, in addition to the data type itself. The old way of creating extension data references is deprecated and will be removed in a future release. + + For example, the following code: + + ```ts + export const myExtension = + createExtensionDataRef('my-plugin.my-data'); + ``` + + Should be updated to the following: + + ```ts + export const myExtension = createExtensionDataRef().with({ + id: 'my-plugin.my-data', + }); + ``` + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/repo-tools@0.9.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + +## @backstage/test-utils@1.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-api-docs@0.11.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-app-backend@0.3.72-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.23-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-app-node@0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + +## @backstage/plugin-app-visualizer@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-auth-backend@0.22.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.0 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.0 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.0 + +### Patch Changes + +- 39f36a9: Updated the Microsoft authenticator to accurately define required scopes, but to also omit the required and additional scopes when requesting resource scopes. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-node@0.4.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-react@0.1.5-next.0 + +### Patch Changes + +- aeac3e9: feat: Hide visibility of CookieAuthRedirect +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + +## @backstage/plugin-catalog@1.21.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-catalog-backend@1.24.1-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.3.18-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- 90a7340: `AwsOrganizationCloudAccountProcessor` configuration field `roleArn` is deprecated in favor of new field `accountId` +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-github@0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-logs@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.31-next.0 + +### Patch Changes + +- 58dff4d: Added option to ingest groups based on their group membership in Azure Entra ID +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-catalog-graph@0.4.8-next.0 + +### Patch Changes + +- fba7537: Memoize entity graph nodes when applying an `entityFilter` to prevent repeated redraws +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-node@1.12.5-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-catalog-react@1.12.3-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- 9b89b82: Internal refactor to remove unnecessary `routable` prop in the implementation of the `createEntityContentExtension` alpha export. +- bebd569: Fix extra divider displayed on user list picker component +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-config-schema@0.1.58-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-devtools-backend@0.3.9-next.0 + +### Patch Changes + +- 32a38e1: Removed unused code for lockfile analysis. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-events-backend@0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.9-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-azure@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-github@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-node@0.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + +## @backstage/plugin-home@0.7.8-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- fdcc059: Fixed a bug on the WelcomeTitle component where the welcome message wasn't correct when the language was set to Spanish +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + +## @backstage/plugin-home-react@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes@0.11.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + +## @backstage/plugin-kubernetes-backend@0.18.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-node@0.1.17-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + +## @backstage/plugin-kubernetes-node@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-kubernetes-react@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-notifications@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-notifications-backend@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## @backstage/plugin-notifications-backend-module-email@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + +## @backstage/plugin-notifications-node@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## @backstage/plugin-org@0.6.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-org-react@0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-permission-backend@0.5.47-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-permission-node@0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-proxy-backend@0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder@1.23.1-next.0 + +### Patch Changes + +- bbd9f56: Cleaned up codebase of RepoUrlPicker +- b8600fe: Fix issue with `RepoUrlPicker` not refreshing the credentials for a different host +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/plugin-scaffolder-backend@1.23.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.47-next.0 + +### Patch Changes + +- dae85df: Add examples for `fetch:cookiecutter` scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + +### Patch Changes + +- fad1b90: Allow the `createGitlabProjectVariableAction` to use oauth tokens + +- aab708e: Added test cases for gitlab:issue:edit examples + +- ef742dc: Added test cases for gitlab:projectAccessToken:create example + +- 1ba4c2f: Added test cases for gitlab:pipeline:trigger examples + +- a6603e4: Add custom action for merge request: **auto** + + The **Auto** action selects the committed action between _create_ and _update_. + + The **Auto** action fetches files using the **/projects/repository/tree endpoint**. + After fetching, it checks if the file exists locally and in the repository. If it does, it chooses **update**; otherwise, it chooses **create**. + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.6-next.0 + +### Patch Changes + +- 6fc03c7: Add examples for notification:send scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.0 + +### Patch Changes + +- 449def7: Add examples for fetch:rails scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.0 + +## @backstage/plugin-scaffolder-node@0.4.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-test-utils@0.4.5-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-search@1.4.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend@1.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-pg@0.5.33-next.0 + +### Patch Changes + +- 7251567: Removing `@backstage/backend-app-api` dependency +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + +## @backstage/plugin-search-backend-node@1.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-react@1.7.14-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-signals@0.0.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-signals-backend@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## @backstage/plugin-signals-node@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-techdocs@1.10.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-backend@1.10.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-node@1.12.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-techdocs-react@1.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-user-settings@0.8.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.100-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-devtools@0.1.17-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + +## example-app-next@0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-app-visualizer@0.1.9-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + +## app-next-example-plugin@0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + +## example-backend@0.0.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-notifications-backend@0.3.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + +## example-backend-legacy@0.2.101-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.0 + - example-app@0.2.100-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + +## e2e-test@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.18-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.99-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @internal/plugin-todo-list@1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @internal/plugin-todo-list-backend@1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 diff --git a/docs/releases/v1.30.0-next.1-changelog.md b/docs/releases/v1.30.0-next.1-changelog.md new file mode 100644 index 0000000000..1d93235740 --- /dev/null +++ b/docs/releases/v1.30.0-next.1-changelog.md @@ -0,0 +1,2175 @@ +# Release v1.30.0-next.1 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.30.0-next.1](https://backstage.github.io/upgrade-helper/?to=1.30.0-next.1) + +## @backstage/core-app-api@1.14.2-next.0 + +### Patch Changes + +- 9a46a81: The request to delete the session cookie when running the app in protected mode is now done with a plain `fetch` rather than `FetchApi`. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - + +## @backstage/config-loader@1.9.0-next.1 + +### Minor Changes + +- 274428f: Add configuration key to File and Remote `ConfigSource`s that enables configuration of parsing logic. Previously limited to yaml, these `ConfigSource`s now allow for a multitude of parsing options (e.g. JSON). + +### Patch Changes + +- 1edd6c2: The `env` option of `ConfigSources.default` now correctly allows undefined members. +- 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-notifications-backend-module-email@0.2.0-next.1 + +### Minor Changes + +- def53a7: **BREAKING** Following `NotificationTemplateRenderer` methods now return a Promise and **must** be awaited: `getSubject`, `getText` and `getHtml`. + + Required changes and example usage: + + ```diff + import { notificationsEmailTemplateExtensionPoint } from '@backstage/plugin-notifications-backend-module-email'; + import { Notification } from '@backstage/plugin-notifications-common'; + +import { getNotificationSubject, getNotificationTextContent, getNotificationHtmlContent } from 'my-notification-processing-library` + export const notificationsModuleEmailDecorator = createBackendModule({ + pluginId: 'notifications', + moduleId: 'email.templates', + register(reg) { + reg.registerInit({ + deps: { + emailTemplates: notificationsEmailTemplateExtensionPoint, + }, + async init({ emailTemplates }) { + emailTemplates.setTemplateRenderer({ + - getSubject(notification) { + + async getSubject(notification) { + - return `New notification from ${notification.source}`; + + const subject = await getNotificationSubject(notification); + + return `New notification from ${subject}`; + }, + - getText(notification) { + + async getText(notification) { + - return notification.content; + + const text = await getNotificationTextContent(notification); + + return text; + }, + - getHtml(notification) { + + async getHtml(notification) { + - return `

${notification.content}

`; + + const html = await getNotificationHtmlContent(notification); + + return html; + }, + }); + }, + }); + }, + }); + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration-aws-node@0.1.12 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.1 + +## @backstage/plugin-techdocs-common@0.1.0-next.0 + +### Minor Changes + +- 4698e1f: Initial release of the techdocs-common package. + +## @backstage/app-defaults@1.5.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @backstage/backend-app-api@0.8.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/backend-common@0.23.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/backend-defaults@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-app-api@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/backend-dynamic-feature-service@0.2.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-app-api@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-app-node@0.1.23-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-backend@0.3.10-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/backend-openapi-utils@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/errors@1.2.4 + +## @backstage/backend-plugin-api@0.7.1-next.1 + +### Patch Changes + +- f011d1b: fix typo in `getPluginRequestToken` comments +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/backend-tasks@0.5.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-app-api@0.8.1-next.1 + - @backstage/backend-defaults@0.4.2-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/cli@0.27.0-next.1 + +### Patch Changes + +- e6e7d86: Switched the target from `'ES2022'` to `'es2022'` for better compatibility with older versions of `swc`. +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.2.8-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.18-next.1 + +### Patch Changes + +- 6c1081c: Updated dockerfile and `app-config.production.yaml` to make it easier to get started with example data +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/dev-utils@1.0.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + +## @backstage/frontend-app-api@0.7.5-next.1 + +### Patch Changes + +- 3be9aeb: Added support for v2 extensions, which declare their inputs and outputs without using a data map. +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-plugin-api@0.6.8-next.1 + +### Patch Changes + +- 3be9aeb: Extensions have been changed to be declared with an array of inputs and outputs, rather than a map of named data refs. This change was made to reduce confusion around the role of the input and output names, as well as enable more powerful APIs for overriding extensions. + + An extension that was previously declared like this: + + ```tsx + const exampleExtension = createExtension({ + name: 'example', + inputs: { + items: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + element: coreExtensionData.reactElement, + }, + factory({ inputs }) { + return { + element: ( +
+ Example + {inputs.items.map(item => { + return
{item.output.element}
; + })} +
+ ), + }; + }, + }); + ``` + + Should be migrated to the following: + + ```tsx + const exampleExtension = createExtension({ + name: 'example', + inputs: { + items: createExtensionInput([coreExtensionData.reactElement]), + }, + output: [coreExtensionData.reactElement], + factory({ inputs }) { + return [ + coreExtensionData.reactElement( +
+ Example + {inputs.items.map(item => { + return
{item.get(coreExtensionData.reactElement)}
; + })} +
, + ), + ]; + }, + }); + ``` + +- 3fb421d: Added support to be able to define `zod` config schema in Blueprints, with built in schema merging from the Blueprint and the extension instances. + +- 6349099: Added config input type to the extensions + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.12-next.1 + +### Patch Changes + +- 3be9aeb: Added support for v2 extensions, which declare their inputs and outputs without using a data map. +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/test-utils@1.5.10-next.1 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.9.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.9-next.1 + - @backstage/backend-defaults@0.4.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + +## @backstage/test-utils@1.5.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + +## @backstage/plugin-api-docs@0.11.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-app-backend@0.3.72-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-app-node@0.1.23-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-app-node@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + +## @backstage/plugin-app-visualizer@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-auth-backend@0.22.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.1 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.1 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.1 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-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-azure-easyauth-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-backend@0.22.10-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-backend@0.22.10-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.2.4-next.1 + +### Patch Changes + +- c8f1cae: Add `signIn` to authentication provider configuration schema +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-auth-node@0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-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.2-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend@1.24.1-next.1 + +### Patch Changes + +- 51240ee: Preserve default `allowedLocationTypes` when `setAllowedLocationTypes()` of `CatalogLocationsExtensionPoint` is not called. +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.1 + - @backstage/backend-openapi-utils@0.1.16-next.1 + - @backstage/backend-tasks@0.5.28-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-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-azure@0.1.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-openapi-utils@0.1.16-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-github@0.6.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.1 + +### Patch Changes + +- c7b14ed: Adds new optional `excludeRepos` configuration option to the Gitlab catalog provider. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-ldap@0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-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-backend-module-logs@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-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-backend-module-scaffolder-entity-model@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.4-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-catalog-common@1.0.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-graph@0.4.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + +## @backstage/plugin-catalog-node@1.12.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-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-react@1.12.3-next.1 + +### Patch Changes + +- 7ca331c: Correct `EntityDisplayName`'s icon alignment with the text. +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-catalog-unprocessed-entities-common@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + +## @backstage/plugin-devtools@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-devtools-common@0.1.12-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-devtools-backend@0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-devtools-common@0.1.12-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools-common@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend@0.3.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-backend-module-azure@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-backend-module-github@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-events-node@0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + +## @backstage/plugin-home@0.7.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + +## @backstage/plugin-kubernetes@0.11.13-next.1 + +### Patch Changes + +- e6c15cc: Adds support for Backstage's new frontend system, available via the `/alpha` sub-path export. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.1 + +## @backstage/plugin-kubernetes-backend@0.18.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-common@0.8.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 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-kubernetes-node@0.1.17-next.1 + +## @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.1 + +## @backstage/plugin-kubernetes-common@0.8.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-notifications-backend@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-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.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.1 + - @backstage/plugin-signals-node@0.1.9-next.1 + +## @backstage/plugin-notifications-node@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.9-next.1 + +## @backstage/plugin-org@0.6.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-org-react@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-permission-backend@0.5.47-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-permission-common@0.8.1-next.0 + +### Patch Changes + +- 137fa34: Add the MetadataResponseSerializedRule type from @backstage/plugin-permission-node, since this type might be used in frontend code. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.8.1-next.1 + +### Patch Changes + +- 5cd9878: The MetadataResponseSerializedRule type has been moved to @backstage/plugin-permission-common, and should be imported from there going forward. To avoid an immediate breaking change, this type is still re-exported from this package, but is marked as deprecated and will be removed in a future release. +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @backstage/plugin-permission-react@0.4.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-proxy-backend@0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder@1.23.1-next.1 + +### Patch Changes + +- 896a22d: Fix helper text margin for scaffolder EntityNamePicker and EntityTagsPicker when using outlined text field +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend@1.23.1-next.1 + +### Patch Changes + +- ef87e06: Fix scaffolder action `catalog:write` to write to directories that don't already exist +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.1 + - @backstage/backend-tasks@0.5.28-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-node@0.4.18-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.1 + +### Patch Changes + +- e3b64be: Added examples for publish:bitbucketServer action and improve its test cases +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.47-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.1 + +### Patch Changes + +- 24de005: Added test cases for publish:gitea examples +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.1 + +### Patch Changes + +- d21d307: Added examples for github:environment:create action and improve its test cases +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.1 + +## @backstage/plugin-scaffolder-common@1.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.4.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.1 + - @backstage/backend-test-utils@0.4.5-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## @backstage/plugin-scaffolder-react@1.11.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-search@1.4.15-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-search-backend@1.5.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/backend-defaults@0.4.2-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-backend-module-catalog@0.1.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-tasks@0.5.28-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-search-backend-module-elasticsearch@1.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-explore@0.1.29-next.1 + +### Patch Changes + +- 93fc1a0: Updated dependency `@backstage-community/plugin-explore-common` to `^0.0.4`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-pg@0.5.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-techdocs@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.9-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-node@1.2.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-search-common@1.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.14-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-signals-backend@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + - @backstage/plugin-signals-node@0.1.9-next.1 + +## @backstage/plugin-signals-node@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## @backstage/plugin-techdocs@1.10.8-next.1 + +### Patch Changes + +- 69bd940: Use annotation constants from new techdocs-common package. +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-techdocs-common@0.1.0-next.0 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/test-utils@1.5.10-next.1 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-backend@1.10.10-next.1 + +### Patch Changes + +- 69bd940: Use annotation constants from new techdocs-common package. +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.9-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-techdocs-common@0.1.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.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-techdocs-node@1.12.9-next.1 + +### Patch Changes + +- 69bd940: Use annotation constants from new techdocs-common package. +- 949083d: Update `patchMkdocsYmlPrebuild` to modify `repo_url` and `edit_uri` independently. +- Updated dependencies + - @backstage/plugin-techdocs-common@0.1.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-user-settings@0.8.11-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-signals-node@0.1.9-next.1 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.100-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/cli@0.27.0-next.1 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/plugin-user-settings@0.8.11-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-catalog-graph@0.4.8-next.1 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-devtools@0.1.17-next.1 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## example-app-next@0.0.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/cli@0.27.0-next.1 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-user-settings@0.8.11-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-catalog-graph@0.4.8-next.1 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-app-visualizer@0.1.9-next.1 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## app-next-example-plugin@0.0.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-components@0.14.10-next.0 + +## example-backend@0.0.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.1 + - @backstage/plugin-techdocs-backend@1.10.10-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-scaffolder-backend@1.23.1-next.1 + - @backstage/plugin-auth-backend@0.22.10-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.1 + - @backstage/backend-defaults@0.4.2-next.1 + - @backstage/plugin-app-backend@0.3.72-next.1 + - @backstage/plugin-devtools-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.5.4-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.1 + - @backstage/plugin-kubernetes-backend@0.18.4-next.1 + - @backstage/plugin-permission-backend@0.5.47-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.1 + - @backstage/plugin-search-backend@1.5.15-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.1 + - @backstage/plugin-notifications-backend@0.3.4-next.1 + - @backstage/plugin-signals-backend@0.1.9-next.1 + +## example-backend-legacy@0.2.101-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.10.10-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.1 + - @backstage/plugin-scaffolder-backend@1.23.1-next.1 + - @backstage/plugin-auth-backend@0.22.10-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.1 + - example-app@0.2.100-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-app-backend@0.3.72-next.1 + - @backstage/plugin-devtools-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.5.4-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-backend@0.18.4-next.1 + - @backstage/plugin-permission-backend@0.5.47-next.1 + - @backstage/plugin-search-backend@1.5.15-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.1 + - @backstage/plugin-events-backend@0.3.10-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.1 + - @backstage/plugin-signals-backend@0.1.9-next.1 + - @backstage/plugin-signals-node@0.1.9-next.1 + +## e2e-test@0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.18-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.99-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/cli@0.27.0-next.1 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/test-utils@1.5.10-next.1 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @internal/plugin-todo-list-backend@1.0.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## @internal/plugin-todo-list-common@1.0.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 diff --git a/docs/releases/v1.30.0-next.2-changelog.md b/docs/releases/v1.30.0-next.2-changelog.md new file mode 100644 index 0000000000..cdf4164566 --- /dev/null +++ b/docs/releases/v1.30.0-next.2-changelog.md @@ -0,0 +1,156 @@ +# Release v1.30.0-next.2 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.30.0-next.2](https://backstage.github.io/upgrade-helper/?to=1.30.0-next.2) + +## @backstage/cli@0.27.0-next.2 + +### Patch Changes + +- b2d97fd: Fixing loading of additional config files with new `ConfigSources` +- adabb40: New command now supports setting package license +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.9.0-next.1 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.14.0-next.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/create-app@0.5.18-next.2 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/plugin-catalog-graph@0.4.8-next.2 + +### Patch Changes + +- 4a529c2: Use `entityPresentationApi` for the node title and the icon. +- Updated dependencies + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + +## example-app@0.2.100-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.2 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-devtools@0.1.17-next.1 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.11-next.1 + +## example-app-next@0.0.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.2 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-app-visualizer@0.1.9-next.1 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.11-next.1 + +## e2e-test@0.2.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.18-next.2 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.99-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.2 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/test-utils@1.5.10-next.1 + - @backstage/theme@0.5.6 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-techdocs-react@1.2.7-next.0 diff --git a/docs/releases/v1.30.0-next.3-changelog.md b/docs/releases/v1.30.0-next.3-changelog.md new file mode 100644 index 0000000000..4fa86da821 --- /dev/null +++ b/docs/releases/v1.30.0-next.3-changelog.md @@ -0,0 +1,2199 @@ +# Release v1.30.0-next.3 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.30.0-next.3](https://backstage.github.io/upgrade-helper/?to=1.30.0-next.3) + +## @backstage/backend-plugin-api@0.8.0-next.2 + +### Minor Changes + +- 7c5f3b0: The `createServiceRef` function now accepts a new boolean `multiple` option. The `multiple` option defaults to `false` and when set to `true`, it enables that multiple implementation are installed for the created service ref. + + We're looking for ways to make it possible to augment services without the need to replace the entire service. + + Typical example of that being the ability to install support for additional targets for the `UrlReader` service without replacing the service itself. This achieves that by allowing us to define services that can have multiple simultaneous implementation, allowing the `UrlReader` implementation to depend on such a service to collect all possible implementation of support for external targets: + + ```diff + // @backstage/backend-defaults + + + export const urlReaderFactoriesServiceRef = createServiceRef({ + + id: 'core.urlReader.factories', + + scope: 'plugin', + + multiton: true, + + }); + + ... + + export const urlReaderServiceFactory = createServiceFactory({ + service: coreServices.urlReader, + deps: { + config: coreServices.rootConfig, + logger: coreServices.logger, + + factories: urlReaderFactoriesServiceRef, + }, + - async factory({ config, logger }) { + + async factory({ config, logger, factories }) { + return UrlReaders.default({ + config, + logger, + + factories, + }); + }, + }); + ``` + + With that, you can then add more custom `UrlReader` factories by installing more implementations of the `urlReaderFactoriesServiceRef` in your backend instance. Something like: + + ```ts + // packages/backend/index.ts + import { createServiceFactory } from '@backstage/backend-plugin-api'; + import { urlReaderFactoriesServiceRef } from '@backstage/backend-defaults'; + ... + + backend.add(createServiceFactory({ + service: urlReaderFactoriesServiceRef, + deps: {}, + async factory() { + return CustomUrlReader.factory; + }, + })); + + ... + + ``` + +### Patch Changes + +- 6061061: Added `createBackendFeatureLoader`, which can be used to create an installable backend feature that can in turn load in additional backend features in a dynamic way. + +- ba9abf4: The `SchedulerService` now allows tasks with `frequency: { trigger: 'manual' }`. This means that the task will not be scheduled, but rather run only when manually triggered with `SchedulerService.triggerTask`. + +- 8b13183: Added `createBackendFeatureLoader`, which can be used to programmatically select and install backend features. + + A feature loader can return an list of features to be installed, for example in the form on an `Array` or other for of iterable, which allows for the loader to be defined as a generator function. Both synchronous and asynchronous loaders are supported. + + Additionally, a loader can depend on services in its implementation, with the restriction that it can only depend on root-scoped services, and it may not override services that have already been instantiated. + + ```ts + const searchLoader = createBackendFeatureLoader({ + deps: { + config: coreServices.rootConfig, + }, + *loader({ config }) { + // Example of a custom config flag to enable search + if (config.getOptionalString('customFeatureToggle.search')) { + yield import('@backstage/plugin-search-backend/alpha'); + yield import('@backstage/plugin-search-backend-module-catalog/alpha'); + yield import('@backstage/plugin-search-backend-module-explore/alpha'); + yield import('@backstage/plugin-search-backend-module-techdocs/alpha'); + } + }, + }); + ``` + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/frontend-plugin-api@0.7.0-next.2 + +### Minor Changes + +- 72754db: **BREAKING**: All types of route refs are always considered optional by `useRouteRef`, which means the caller must always handle a potential `undefined` return value. Related to this change, the `optional` option from `createExternalRouteRef` has been removed, since it is no longer necessary. + + This is released as an immediate breaking change as we expect the usage of the new route refs to be extremely low or zero, since plugins that support the new system will still use route refs and `useRouteRef` from `@backstage/core-plugin-api` in combination with `convertLegacyRouteRef` from `@backstage/core-compat-api`. + +### Patch Changes + +- 210d066: Added support for using the `params` in other properties of the `createExtensionBlueprint` options by providing a callback. +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-auth-node@0.5.0-next.2 + +### Minor Changes + +- 579afd0: **BREAKING**: Sign-in resolvers configured via `.signIn.resolvers` now take precedence over sign-in resolvers passed to `signInResolver` option of `createOAuthProviderFactory`. This effectively makes sign-in resolvers passed via the `signInResolver` the default one, which you can then override through configuration. + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @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.22.0-next.2 + +### Minor Changes + +- 6925dcb: Introduces the HasSubdomainsCard component that displays the subdomains of a given domain + +### Patch Changes + +- 604a504: The entity relation cards available for the new frontend system via `/alpha` now have more accurate and granular default filters. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder@1.24.0-next.2 + +### Minor Changes + +- 3fca643: Added field extension `RepoBranchPicker` that supports autocompletion for Bitbucket + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.11.0-next.2 + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + +## @backstage/app-defaults@1.5.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @backstage/backend-app-api@0.8.1-next.2 + +### Patch Changes + +- 8b13183: Added support for the latest version of `BackendFeature`s from `@backstage/backend-plugin-api`, including feature loaders. +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 7c5f3b0: Update the `ServiceRegister` implementation to enable registering multiple service implementations for a given service ref. +- 80a0737: Added configuration for the `packages` options to config schema +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/cli-node@0.2.7 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-common@0.23.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.4.2-next.2 + +### Patch Changes + +- 0d16b52: Add access restrictions to the JWKS external access method config schema +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- ba9abf4: The `SchedulerService` now allows tasks with `frequency: { trigger: 'manual' }`. This means that the task will not be scheduled, but rather run only when manually triggered with `SchedulerService.triggerTask`. +- 7c5f3b0: Update the `UrlReader` service to depends on multiple instances of `UrlReaderFactoryProvider` service. +- 1d5f298: Avoid excessive numbers of error listeners on cache clients +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-app-api@0.8.1-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-dynamic-feature-service@0.2.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-app-api@0.8.1-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-app-node@0.1.23-next.2 + - @backstage/plugin-events-backend@0.3.10-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/cli-node@0.2.7 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-openapi-utils@0.1.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/errors@1.2.4 + +## @backstage/backend-tasks@0.5.28-next.2 + +### Patch Changes + +- ba9abf4: The `PluginTaskScheduler` now allows tasks with `frequency: { trigger: 'manual' }`. This means that the task will not be scheduled, but rather run only when manually triggered with `PluginTaskScheduler.triggerTask`. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.4.5-next.2 + +### Patch Changes + +- 8b13183: Internal updates to support latest version of `BackendFeauture`s from `@backstage/backend-plugin-api`. +- 7c5f3b0: Update the `ServiceFactoryTester` to be able to test services that enables multi implementation installation. +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.2 + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-app-api@0.8.1-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/cli@0.27.0-next.3 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/config-loader@1.9.0-next.2 + - @backstage/cli-node@0.2.7 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/config-loader@1.9.0-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.2.8-next.2 + +### Patch Changes + +- 72754db: Updated usage of `useRouteRef`, which can now always return `undefined`. +- 16cf96c: Both `compatWrapper` and `convertLegacyRouteRef` now support converting from the new system to the old. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.18-next.3 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/dev-utils@1.0.37-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/app-defaults@1.5.10-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + +## @backstage/frontend-app-api@0.7.5-next.2 + +### Patch Changes + +- 72754db: Updated usage of `useRouteRef`, which can now always return `undefined`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.12-next.2 + +### Patch Changes + +- 8209449: Added new APIs for testing extensions +- 72754db: Updated usage of `useRouteRef`, which can now always return `undefined`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/frontend-app-api@0.7.5-next.2 + - @backstage/test-utils@1.5.10-next.2 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.9.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/cli-node@0.2.7 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.2 + - @backstage/plugin-techdocs-node@1.12.9-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + +## @backstage/test-utils@1.5.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + +## @backstage/plugin-api-docs@0.11.8-next.2 + +### Patch Changes + +- 4b6d2cb: Updated dependency `@graphiql/react` to `^0.23.0`. +- Updated dependencies + - @backstage/plugin-catalog@1.22.0-next.2 + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-app-backend@0.3.72-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-app-node@0.1.23-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-app-node@0.1.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/config-loader@1.9.0-next.2 + +## @backstage/plugin-app-visualizer@0.1.9-next.2 + +### Patch Changes + +- 72754db: Updated usage of `useRouteRef`, which can now always return `undefined`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-auth-backend@0.22.10-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.2 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.2 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.2 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.2 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.2 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.2 + - @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.2 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-backend@0.22.10-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-backend@0.22.10-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/config@1.2.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-bitbucket-cloud-common@0.2.22-next.1 + +### Patch Changes + +- 3fca643: Added method `listBranchesByRepository` to `BitbucketCloudClient` +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + +## @backstage/plugin-catalog-backend@1.24.1-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/backend-openapi-utils@0.1.16-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-azure@0.1.43-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/backend-openapi-utils@0.1.16-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.1 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.37-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.40-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-github@0.6.6-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-ldap@0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-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-backend-module-logs@0.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.31-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.29-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.4-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-common@1.0.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-graph@0.4.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + +## @backstage/plugin-catalog-node@1.12.5-next.2 + +### Patch Changes + +- 7c5f3b0: Explicit declare if the service ref accepts `single` or `multiple` implementations. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-catalog-common@1.0.26-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-react@1.12.3-next.2 + +### Patch Changes + +- 012e3eb: Entity page extensions created for the new frontend system via the `/alpha` exports will now be enabled by default. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-catalog-unprocessed-entities-common@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + +## @backstage/plugin-devtools@0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-devtools-common@0.1.12-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-devtools-backend@0.3.9-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-devtools-common@0.1.12-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools-common@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend@0.3.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend-module-azure@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## @backstage/plugin-events-backend-module-gerrit@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## @backstage/plugin-events-backend-module-github@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-test-utils@0.1.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.2 + +## @backstage/plugin-events-node@0.3.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + +## @backstage/plugin-home@0.7.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + +## @backstage/plugin-kubernetes@0.11.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.2 + +## @backstage/plugin-kubernetes-backend@0.18.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 8c1aa06: Add `kubernetes.clusterLocatorMethods[].clusters[].customResources` to the configuration schema. + This was already documented and supported by the plugin. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-kubernetes-node@0.1.17-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/integration-aws-node@0.1.12 + - @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-kubernetes-cluster@0.0.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.2 + +## @backstage/plugin-kubernetes-common@0.8.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.17-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.4.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-notifications-backend@0.3.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-notifications-node@0.2.4-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @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.5 + +## @backstage/plugin-notifications-backend-module-email@0.2.0-next.2 + +### Patch Changes + +- cdb630d: Add support for stream transport for debugging purposes +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-notifications-node@0.2.4-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration-aws-node@0.1.12 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + +## @backstage/plugin-notifications-node@0.2.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + +## @backstage/plugin-org@0.6.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-org-react@0.1.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-permission-backend@0.5.47-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + +## @backstage/plugin-permission-common@0.8.1-next.1 + +### Patch Changes + +- df784fe: Add the MetadataResponse type from @backstage/plugin-permission-node, since this + type might be used in frontend code. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.8.1-next.2 + +### Patch Changes + +- df784fe: The MetadataResponse type has been moved to @backstage/plugin-permission-common + to match the recent move of MetadataResponseSerializedRule, and should be + imported from there going forward. To avoid an immediate breaking change, this + type is still re-exported from this package, but is marked as deprecated and + will be removed in a future release. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-permission-react@0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-proxy-backend@0.5.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend@1.23.1-next.2 + +### Patch Changes + +- c544f81: Add support for status filtering in scaffolder tasks endpoint +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.2 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 3fca643: Added autocompletion support for resource `branches` +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.47-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-notifications-node@0.2.4-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-notifications-common@0.0.5 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.31-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 382e868: Added test cases for sentry:project:create examples +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.4.9-next.2 + +### Patch Changes + +- c544f81: Add support for status filtering in scaffolder tasks endpoint +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@0.4.5-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-react@1.11.0-next.2 + +### Patch Changes + +- 072c00c: Fixed a bug in `DefaultTableOutputs` where output elements overlapped on smaller screen sizes +- 04759f2: Fix null check in `isJsonObject` utility function for scaffolder review state component +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-search@1.4.15-next.2 + +### Patch Changes + +- 3123c16: Fix package metadata +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-search-backend@1.5.15-next.2 + +### Patch Changes + +- 3123c16: Fix package metadata +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.2 + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-openapi-utils@0.1.16-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-backend-module-catalog@0.1.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-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-search-backend-module-elasticsearch@1.5.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/integration-aws-node@0.1.12 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-explore@0.1.29-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-pg@0.5.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.16-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-techdocs@0.1.28-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-techdocs-node@1.12.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-node@1.2.28-next.2 + +### Patch Changes + +- 3123c16: Fix package metadata +- 7c5f3b0: Explicit declare if the service ref accepts `single` or `multiple` implementations. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-search-common@1.2.14-next.1 + +### Patch Changes + +- 3123c16: Fix package metadata +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.14-next.2 + +### Patch Changes + +- 3123c16: Fix package metadata +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-signals-backend@0.1.9-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-signals-node@0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-techdocs@1.10.8-next.2 + +### Patch Changes + +- 67e76f2: TechDocs now supports the `mkdocs-redirects` plugin. Redirects defined using the `mkdocs-redirect` plugin will be handled automatically in TechDocs. Redirecting to external urls is not supported. In the case that an external redirect url is provided, TechDocs will redirect to the current documentation site home. +- bdc5471: Fixed issue where header styles were incorrectly generated when themes used CSS variables to define font size. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-techdocs-common@0.1.0-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.37-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.22.0-next.2 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-techdocs@1.10.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/test-utils@1.5.10-next.2 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-backend@1.10.10-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-techdocs-node@1.12.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-techdocs-common@0.1.0-next.0 + +## @backstage/plugin-techdocs-node@1.12.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-techdocs-common@0.1.0-next.0 + +## @backstage/plugin-user-settings@0.8.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.100-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.11.0-next.2 + - @backstage/plugin-catalog@1.22.0-next.2 + - @backstage/cli@0.27.0-next.3 + - @backstage/frontend-app-api@0.7.5-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-search@1.4.15-next.2 + - @backstage/plugin-api-docs@0.11.8-next.2 + - @backstage/plugin-techdocs@1.10.8-next.2 + - @backstage/plugin-scaffolder@1.24.0-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.3 + - @backstage/plugin-catalog-import@0.12.2-next.2 + - @backstage/plugin-org@0.6.28-next.2 + - @backstage/plugin-user-settings@0.8.11-next.2 + - @backstage/plugin-devtools@0.1.17-next.2 + - @backstage/plugin-home@0.7.9-next.2 + - @backstage/plugin-kubernetes@0.11.13-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/app-defaults@1.5.10-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.2 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## example-app-next@0.0.14-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.11.0-next.2 + - @backstage/plugin-catalog@1.22.0-next.2 + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/cli@0.27.0-next.3 + - @backstage/frontend-app-api@0.7.5-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-app-visualizer@0.1.9-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-search@1.4.15-next.2 + - @backstage/plugin-api-docs@0.11.8-next.2 + - @backstage/plugin-techdocs@1.10.8-next.2 + - @backstage/plugin-scaffolder@1.24.0-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.3 + - @backstage/plugin-catalog-import@0.12.2-next.2 + - @backstage/plugin-org@0.6.28-next.2 + - @backstage/plugin-user-settings@0.8.11-next.2 + - @backstage/plugin-home@0.7.9-next.2 + - @backstage/plugin-kubernetes@0.11.13-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/app-defaults@1.5.10-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.2 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## app-next-example-plugin@0.0.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-components@0.14.10-next.0 + +## example-backend@0.0.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.2 + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-backend@1.23.1-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.2 + - @backstage/plugin-notifications-backend@0.3.4-next.2 + - @backstage/plugin-kubernetes-backend@0.18.4-next.2 + - @backstage/plugin-permission-backend@0.5.47-next.2 + - @backstage/plugin-devtools-backend@0.3.9-next.2 + - @backstage/plugin-techdocs-backend@1.10.10-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-signals-backend@0.1.9-next.2 + - @backstage/plugin-proxy-backend@0.5.4-next.2 + - @backstage/plugin-auth-backend@0.22.10-next.2 + - @backstage/plugin-app-backend@0.3.72-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-backend@1.5.15-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.2 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.2 + - @backstage/catalog-model@1.5.0 + +## example-backend-legacy@0.2.101-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.23.1-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.2 + - @backstage/plugin-kubernetes-backend@0.18.4-next.2 + - @backstage/plugin-permission-backend@0.5.47-next.2 + - @backstage/plugin-devtools-backend@0.3.9-next.2 + - @backstage/plugin-techdocs-backend@1.10.10-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-signals-backend@0.1.9-next.2 + - @backstage/plugin-proxy-backend@0.5.4-next.2 + - @backstage/plugin-auth-backend@0.22.10-next.2 + - @backstage/plugin-app-backend@0.3.72-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-backend@1.5.15-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.2 + - @backstage/plugin-events-backend@0.3.10-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## e2e-test@0.2.19-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.18-next.3 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.99-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.22.0-next.2 + - @backstage/cli@0.27.0-next.3 + - @backstage/plugin-techdocs@1.10.8-next.2 + - @backstage/test-utils@1.5.10-next.2 + - @backstage/app-defaults@1.5.10-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @internal/plugin-todo-list-backend@1.0.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/errors@1.2.4 + +## @internal/plugin-todo-list-common@1.0.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 diff --git a/docs/releases/v1.6.0-changelog.md b/docs/releases/v1.6.0-changelog.md index 0532243cbf..e9692f4f1b 100644 --- a/docs/releases/v1.6.0-changelog.md +++ b/docs/releases/v1.6.0-changelog.md @@ -248,8 +248,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` @@ -313,8 +312,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` diff --git a/docs/releases/v1.6.0-next.0-changelog.md b/docs/releases/v1.6.0-next.0-changelog.md index 5ff2311b79..fbe9caefde 100644 --- a/docs/releases/v1.6.0-next.0-changelog.md +++ b/docs/releases/v1.6.0-next.0-changelog.md @@ -10,8 +10,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` @@ -69,8 +68,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` diff --git a/docs/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index 234d0d04b7..a6652bd036 100644 --- a/docs/tooling/cli/03-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -26,7 +26,6 @@ repo [command] Command that run across an entire package [command] Lifecycle scripts for individual packages migrate [command] Migration utilities versions:bump [options] Bump Backstage packages to the latest versions -versions:check [options] Check Backstage package versioning clean Delete cache directories [DEPRECATED] build-workspace [packages...] Builds a temporary dist workspace from the provided packages @@ -327,8 +326,7 @@ Options: ## versions\:bump Bump all `@backstage` packages to the latest versions. This checks for updates -in the package registry, and will update entries both in `yarn.lock` and -`package.json` files when necessary. +in the package registry, and will update entries `package.json` files when necessary. ```text Usage: backstage-cli versions:bump [options] @@ -339,23 +337,6 @@ Options: --release Bump to a specific Backstage release line or version (default: "main") ``` -## versions\:check - -Validate `@backstage` dependencies within the repo, making sure that there are -no duplicates of packages that might lead to breakages. - -By supplying the `--fix` flag the command will attempt to fix any conflict that -can be resolved by editing `yarn.lock`, but will not attempt to search for -remote updates or modify any `package.json` files. - -```text -Usage: backstage-cli versions:check [options] - -Options: - --fix Fix any auto-fixable versioning problems - -h, --help display help for command -``` - ## build-workspace Builds a mirror of the workspace using the packaged production version of each diff --git a/docs/tutorials/configuring-plugin-databases.md b/docs/tutorials/configuring-plugin-databases.md index 528d2c6325..db3f126de7 100644 --- a/docs/tutorials/configuring-plugin-databases.md +++ b/docs/tutorials/configuring-plugin-databases.md @@ -36,12 +36,15 @@ Please ensure the appropriate database drivers are installed in your `backend` package. If you intend to use both PostgreSQL and SQLite, you can install both of them. -```bash -# From your Backstage root directory -# install pg if you need PostgreSQL -yarn --cwd packages/backend add pg +Install pg if you need PostgreSQL: -# install SQLite 3 if you intend to set it as the client +```bash title="From your Backstage root directory" +yarn --cwd packages/backend add pg +``` + +Install SQLite 3 if you intend to set it as the client: + +```bash title="From your Backstage root directory" yarn --cwd packages/backend add better-sqlite3 ``` diff --git a/docs/tutorials/enable-public-entry.md b/docs/tutorials/enable-public-entry.md index 6282f66418..25d7382f13 100644 --- a/docs/tutorials/enable-public-entry.md +++ b/docs/tutorials/enable-public-entry.md @@ -100,3 +100,47 @@ With that, Backstage's cli and backend will detect public entry point and serve 5. Finally, as soon as you log in, you will be redirected to the main app home page (inspect the page and see that the protected bundle was served from the app backend after the redirect). That's it! + +## New Frontend System + +If your app uses the new frontend system, you can still use the public entry point feature. The `index-public-experimental.tsx` file does end up looking a bit different in this case: + +```tsx title="in packages/app/src/index-public-experimental.tsx" +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { CookieAuthRedirect } from '@backstage/plugin-auth-react'; +import { createApp } from '@backstage/frontend-app-api'; +import { + coreExtensionData, + createExtension, + createExtensionOverrides, + createSignInPageExtension, +} from '@backstage/frontend-plugin-api'; + +const signInPage = createSignInPageExtension({ + name: 'guest', + loader: async () => props => , +}); + +const authRedirectExtension = createExtension({ + namespace: 'app', + name: 'layout', + attachTo: { id: 'app/root', input: 'children' }, + output: { + element: coreExtensionData.reactElement, + }, + factory: () => ({ + element: , + }), +}); + +const app = createApp({ + features: [ + createExtensionOverrides({ + extensions: [signInPage, authRedirectExtension], + }), + ], +}); + +ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot()); +``` diff --git a/docs/tutorials/switching-sqlite-postgres.md b/docs/tutorials/switching-sqlite-postgres.md index 2ef481dbf3..aec9ca2ee9 100644 --- a/docs/tutorials/switching-sqlite-postgres.md +++ b/docs/tutorials/switching-sqlite-postgres.md @@ -19,8 +19,7 @@ switch between database backends. First, add PostgreSQL to your `backend` package: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add pg ``` diff --git a/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx b/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx index e92c9f2265..c15b9fe208 100644 --- a/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx +++ b/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx @@ -20,7 +20,7 @@ Last year we celebrated 75 [public adopters](https://github.com/backstage/backst ![Accelerated growth of Public Backstage Adopters, from January 2021–December 2022.](assets/2022-12-19/public-backstage-adopters-2022.png) -Not only are our adopters growing at an exponential rate, but so too are our contributors. Our [Discord server](https://discord.gg/backstage-687207715902193673-687207715902193673) is a perfect example of the worlds of our adopters and contributors melding. On average, at any given hour of the day or night, there are more than 500 people online available to talk and provide support on any Backstage topic. Discord discussions run a full gamut of topics – from technical support questions to best practices for onboarding engineers to Backstage – basically, anything and everything an adopter may be interested to know and learn. At the very beginning of 2022, we “only” had 4k Discord members. Today, we have a growing membership of 8.2k. +Not only are our adopters growing at an exponential rate, but so too are our contributors. Our [Discord server](https://discord.gg/backstage-687207715902193673) is a perfect example of the worlds of our adopters and contributors melding. On average, at any given hour of the day or night, there are more than 500 people online available to talk and provide support on any Backstage topic. Discord discussions run a full gamut of topics – from technical support questions to best practices for onboarding engineers to Backstage – basically, anything and everything an adopter may be interested to know and learn. At the very beginning of 2022, we “only” had 4k Discord members. Today, we have a growing membership of 8.2k. Isn’t it what we can call a great and vibrant community of enthusiasts? diff --git a/microsite/data/plugins/azure-storage.yaml b/microsite/data/plugins/azure-storage.yaml index 655a6421ed..6e723c0eeb 100644 --- a/microsite/data/plugins/azure-storage.yaml +++ b/microsite/data/plugins/azure-storage.yaml @@ -4,9 +4,9 @@ author: Deepankumar authorUrl: https://github.com/deepan10 category: Infrastructure description: Explore Azure Storage Blobs in Backstage. -documentation: https://github.com/deepan10/backstage-plugins/tree/main/plugins/azure-storage +documentation: https://github.com/backstage/community-plugins/tree/main/workspaces/azure-storage-explorer/plugins/azure-storage iconUrl: /img/azure-storage-folder.png -npmPackageName: 'backstage-plugin-azure-storage' +npmPackageName: '@backstage-community/plugin-azure-storage-explorer' tags: - Azure - Azure Storage diff --git a/microsite/data/plugins/dora-metrics.yaml b/microsite/data/plugins/dora-metrics.yaml deleted file mode 100644 index 3f59902f46..0000000000 --- a/microsite/data/plugins/dora-metrics.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: DORA Metrics -author: Okay -authorUrl: https://www.okayhq.com -category: Metrics -description: Embed dashboards (like DORA metrics) in your team or service pages from any dev tools (including Github, Gitlab, Jira, Argo, CircleCI, Buildkite, Pagerduty, Rollbar, Sentry, etc). -documentation: https://github.com/OkayHQ/backstage-plugin -iconUrl: /img/okay.png -npmPackageName: '@okayhq/backstage-plugin' -addedDate: '2022-06-16' diff --git a/microsite/data/plugins/infracost.yaml b/microsite/data/plugins/infracost.yaml new file mode 100644 index 0000000000..b6ead655d5 --- /dev/null +++ b/microsite/data/plugins/infracost.yaml @@ -0,0 +1,15 @@ +--- +title: VeeCode Infracost +author: VeeCode Platform +authorUrl: https://platform.vee.codes/ +category: FinOps +description: The Infracost plug-in works in conjunction with terraform and provides a graphical representation and cost estimate data for your entity at your respective provider. +documentation: https://platform.vee.codes/plugin/Infracost +iconUrl: https://veecode-platform.github.io/support/imgs/logo_5.svg +npmPackageName: '@veecode-platform/backstage-plugin-infracost' +tags: + - finops + - infracost + - estimate + - terraform +addedDate: '2024-07-25' diff --git a/microsite/data/plugins/tech-insights.yaml b/microsite/data/plugins/tech-insights.yaml index fbf96df3e6..3bd40d576a 100644 --- a/microsite/data/plugins/tech-insights.yaml +++ b/microsite/data/plugins/tech-insights.yaml @@ -6,7 +6,7 @@ category: Discovery description: Visualize, understand and optimize your team's tech health. documentation: https://roadie.io/backstage/plugins/tech-insights/ iconUrl: https://roadie.io/images/logos/tech-insights.png -npmPackageName: '@backstage/plugin-tech-insights' +npmPackageName: '@backstage-community/plugin-tech-insights' tags: - tech-insights - reporting diff --git a/microsite/docusaurus.config.ts b/microsite/docusaurus.config.ts index b1a6533ab9..67f6de4962 100644 --- a/microsite/docusaurus.config.ts +++ b/microsite/docusaurus.config.ts @@ -241,7 +241,7 @@ const config: Config = { position: 'left', }, { - to: 'docs/releases/v1.28.0', + to: 'docs/releases/v1.29.0', label: 'Releases', position: 'left', }, diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 075025afbb..a0c310ae47 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.29.0", "releases/v1.28.0", "releases/v1.27.0", "releases/v1.26.0", @@ -120,7 +121,8 @@ "features/software-templates/writing-custom-step-layouts", "features/software-templates/authorizing-scaffolder-template-details", "features/software-templates/migrating-to-rjsf-v5", - "features/software-templates/migrating-from-v1beta2-to-v1beta3" + "features/software-templates/migrating-from-v1beta2-to-v1beta3", + "features/software-templates/dry-run-testing" ] }, { @@ -392,6 +394,7 @@ "backend-system/architecture/plugins", "backend-system/architecture/extension-points", "backend-system/architecture/modules", + "backend-system/architecture/feature-loaders", "backend-system/architecture/naming-patterns" ] }, @@ -429,6 +432,7 @@ "backend-system/core-services/permissions", "backend-system/core-services/plugin-metadata", "backend-system/core-services/root-config", + "backend-system/core-services/root-health", "backend-system/core-services/root-http-router", "backend-system/core-services/root-lifecycle", "backend-system/core-services/root-logger", diff --git a/microsite/src/pages/community/index.tsx b/microsite/src/pages/community/index.tsx index c331638c78..a32f5edd13 100644 --- a/microsite/src/pages/community/index.tsx +++ b/microsite/src/pages/community/index.tsx @@ -96,6 +96,11 @@ const Community = () => { url: 'https://tanzu.vmware.com/developer-portal', logo: 'img/partner-logo-tanzubybroadcom.png', }, + { + name: 'StatusNeo', + url: 'https://statusneo.com/backstage', + logo: 'img/partner-logo-statusneo.png', + }, ]; //#endregion diff --git a/microsite/static/img/okay.png b/microsite/static/img/okay.png deleted file mode 100644 index 357219d9d2..0000000000 Binary files a/microsite/static/img/okay.png and /dev/null differ diff --git a/microsite/static/img/partner-logo-statusneo.png b/microsite/static/img/partner-logo-statusneo.png new file mode 100644 index 0000000000..61a676a220 Binary files /dev/null and b/microsite/static/img/partner-logo-statusneo.png differ diff --git a/mkdocs.yml b/mkdocs.yml index f163005377..3b0c7d9caf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -20,7 +20,7 @@ nav: - Support and community: 'overview/support.md' - Logo assets: 'overview/logos.md' - Getting Started: - - Installing a standalone server: 'getting-started/index.md' + - Creating your Backstage App: 'getting-started/index.md' - Configuring Backstage: - Database: 'getting-started/config/database.md' - Authentication: 'getting-started/config/authentication.md' @@ -64,6 +64,7 @@ nav: - Writing Custom Actions: 'features/software-templates/writing-custom-actions.md' - Writing Custom Step Layouts: 'features/software-templates/writing-custom-step-layouts.md' - Migrating from v1beta2 to v1beta3 templates: 'features/software-templates/migrating-from-v1beta2-to-v1beta3.md' + - Dry Run Testing: 'features/software-templates/dry-run-testing.md' - Backstage Search: - Overview: 'features/search/README.md' - Getting Started: 'features/search/getting-started.md' diff --git a/package.json b/package.json index d3d042c2f5..d9b384fb7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.29.0-next.2", + "version": "1.30.0-next.3", "private": true, "repository": { "type": "git", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 21fe959edb..410841fec9 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/app-defaults +## 1.5.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## 1.5.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## 1.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-permission-react@0.4.24 + +## 1.5.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 1.5.8-next.2 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 4393164fcd..284e832ae5 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.5.8-next.2", + "version": "1.5.10-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 5456da237c..62a7b18df0 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,37 @@ # app-next-example-plugin +## 0.0.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-components@0.14.10-next.0 + +## 0.0.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-components@0.14.10-next.0 + +## 0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + +## 0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/frontend-plugin-api@0.6.7 + ## 0.0.13-next.1 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index c3faec66d6..ad179ebbe5 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,6 +1,6 @@ { "name": "app-next-example-plugin", - "version": "0.0.13-next.1", + "version": "0.0.14-next.2", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 22d53e4c78..6382efa811 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,220 @@ # example-app-next +## 0.0.14-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.11.0-next.2 + - @backstage/plugin-catalog@1.22.0-next.2 + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/cli@0.27.0-next.3 + - @backstage/frontend-app-api@0.7.5-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-app-visualizer@0.1.9-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-search@1.4.15-next.2 + - @backstage/plugin-api-docs@0.11.8-next.2 + - @backstage/plugin-techdocs@1.10.8-next.2 + - @backstage/plugin-scaffolder@1.24.0-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.3 + - @backstage/plugin-catalog-import@0.12.2-next.2 + - @backstage/plugin-org@0.6.28-next.2 + - @backstage/plugin-user-settings@0.8.11-next.2 + - @backstage/plugin-home@0.7.9-next.2 + - @backstage/plugin-kubernetes@0.11.13-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/app-defaults@1.5.10-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.2 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## 0.0.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.2 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-app-visualizer@0.1.9-next.1 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.11-next.1 + +## 0.0.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/cli@0.27.0-next.1 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-user-settings@0.8.11-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-catalog-graph@0.4.8-next.1 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-app-visualizer@0.1.9-next.1 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## 0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-app-visualizer@0.1.9-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + +## 0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-app-visualizer@0.1.8 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 0.0.13-next.2 ### Patch Changes diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml index 271040ecec..f6d0174ca1 100644 --- a/packages/app-next/app-config.yaml +++ b/packages/app-next/app-config.yaml @@ -43,6 +43,8 @@ app: - entity-card:org/ownership - entity-card:org/user-profile + - entity-content:kubernetes/kubernetes + # scmAuthExtension: >- # createScmAuthExtension({ # id: 'apis.scmAuth.addons.ghe', diff --git a/packages/app-next/package.json b/packages/app-next/package.json index c38eacfcd5..a12371a135 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.13-next.2", + "version": "0.0.14-next.3", "private": true, "repository": { "type": "git", diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index c911a01258..b57c680474 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -36,18 +36,14 @@ import { convertLegacyApp } from '@backstage/core-compat-api'; import { FlatRoutes } from '@backstage/core-app-api'; import { Route } from 'react-router'; import { CatalogImportPage } from '@backstage/plugin-catalog-import'; -import { - createApiFactory, - configApiRef, - SignInPageProps, -} from '@backstage/core-plugin-api'; +import { createApiFactory, configApiRef } from '@backstage/core-plugin-api'; import { ScmAuth, ScmIntegrationsApi, scmIntegrationsApiRef, } from '@backstage/integration-react'; -import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; -import { SignInPage } from '@backstage/core-components'; +import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha'; +import { signInPageOverrides } from './overrides/SignInPage'; /* @@ -90,12 +86,6 @@ const homePageExtension = createExtension({ }, }); -const signInPage = createSignInPageExtension({ - name: 'guest', - loader: async () => (props: SignInPageProps) => - , -}); - const scmAuthExtension = createApiExtension({ factory: ScmAuth.createDefaultApiFactory(), }); @@ -121,13 +111,14 @@ const app = createApp({ userSettingsPlugin, homePlugin, appVisualizerPlugin, + kubernetesPlugin, + signInPageOverrides, ...collectedLegacyPlugins, createExtensionOverrides({ extensions: [ homePageExtension, scmAuthExtension, scmIntegrationApi, - signInPage, notFoundErrorPage, ], }), diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index 826040a6cb..095c992e18 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -47,9 +47,11 @@ const IndexPage = createPageExtension({ return (
op -
- Page 1 -
+ {page1Link && ( +
+ Page 1 +
+ )}
Home
@@ -82,10 +84,10 @@ const Page1 = createPageExtension({ return (

This is page 1

- Go back + {indexLink && Go back} Page 2 {/* Page 2 */} - Page X + {xLink && Page X}
Sub-page content: @@ -115,7 +117,7 @@ const ExternalPage = createPageExtension({ return (

This is page X

- Go back + {indexLink && Go back}
); }; diff --git a/packages/app-next/src/index-public-experimental.tsx b/packages/app-next/src/index-public-experimental.tsx new file mode 100644 index 0000000000..56bc698ffd --- /dev/null +++ b/packages/app-next/src/index-public-experimental.tsx @@ -0,0 +1,49 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { CookieAuthRedirect } from '@backstage/plugin-auth-react'; +import { createApp } from '@backstage/frontend-app-api'; +import { signInPageOverrides } from './overrides/SignInPage'; +import { + coreExtensionData, + createExtension, + createExtensionOverrides, +} from '@backstage/frontend-plugin-api'; + +const authRedirectExtension = createExtension({ + namespace: 'app', + name: 'layout', + attachTo: { id: 'app/root', input: 'children' }, + output: { + element: coreExtensionData.reactElement, + }, + factory: () => ({ + element: , + }), +}); + +const app = createApp({ + features: [ + signInPageOverrides, + createExtensionOverrides({ + extensions: [authRedirectExtension], + }), + ], +}); + +ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot()); diff --git a/packages/app-next/src/overrides/SignInPage.tsx b/packages/app-next/src/overrides/SignInPage.tsx new file mode 100644 index 0000000000..364a749293 --- /dev/null +++ b/packages/app-next/src/overrides/SignInPage.tsx @@ -0,0 +1,31 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { SignInPage } from '@backstage/core-components'; +import { + createExtensionOverrides, + createSignInPageExtension, +} from '@backstage/frontend-plugin-api'; + +const signInPage = createSignInPageExtension({ + name: 'guest', + loader: async () => props => , +}); + +export const signInPageOverrides = createExtensionOverrides({ + extensions: [signInPage], +}); diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 4977cc1d6d..88e1134800 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,210 @@ # example-app +## 0.2.100-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.11.0-next.2 + - @backstage/plugin-catalog@1.22.0-next.2 + - @backstage/cli@0.27.0-next.3 + - @backstage/frontend-app-api@0.7.5-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-search@1.4.15-next.2 + - @backstage/plugin-api-docs@0.11.8-next.2 + - @backstage/plugin-techdocs@1.10.8-next.2 + - @backstage/plugin-scaffolder@1.24.0-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.3 + - @backstage/plugin-catalog-import@0.12.2-next.2 + - @backstage/plugin-org@0.6.28-next.2 + - @backstage/plugin-user-settings@0.8.11-next.2 + - @backstage/plugin-devtools@0.1.17-next.2 + - @backstage/plugin-home@0.7.9-next.2 + - @backstage/plugin-kubernetes@0.11.13-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/app-defaults@1.5.10-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.2 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## 0.2.100-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.2 + - @backstage/plugin-catalog-graph@0.4.8-next.2 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-devtools@0.1.17-next.1 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.11-next.1 + +## 0.2.100-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.8-next.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-app-api@0.7.5-next.1 + - @backstage/plugin-kubernetes@0.11.13-next.1 + - @backstage/cli@0.27.0-next.1 + - @backstage/plugin-scaffolder@1.23.1-next.1 + - @backstage/plugin-user-settings@0.8.11-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-catalog@1.21.2-next.1 + - @backstage/plugin-search@1.4.15-next.1 + - @backstage/plugin-api-docs@0.11.8-next.1 + - @backstage/plugin-catalog-graph@0.4.8-next.1 + - @backstage/plugin-catalog-import@0.12.2-next.1 + - @backstage/plugin-home@0.7.9-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.1 + - @backstage/plugin-org@0.6.28-next.1 + - @backstage/plugin-scaffolder-react@1.11.0-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/plugin-devtools@0.1.17-next.1 + - @backstage/app-defaults@1.5.10-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## 0.2.100-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-devtools@0.1.17-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + +## 0.2.99 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-devtools@0.1.16 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 0.2.99-next.2 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index f15dbac9db..c4c0c18391 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.99-next.2", + "version": "0.2.100-next.3", "backstage": { "role": "frontend" }, diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 4456d8438b..c7c8883302 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,88 @@ # @backstage/backend-app-api +## 0.8.1-next.2 + +### Patch Changes + +- 8b13183: Added support for the latest version of `BackendFeature`s from `@backstage/backend-plugin-api`, including feature loaders. +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 7c5f3b0: Update the `ServiceRegister` implementation to enable registering multiple service implementations for a given service ref. +- 80a0737: Added configuration for the `packages` options to config schema +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/cli-node@0.2.7 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.8.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## 0.8.0 + +### Minor Changes + +- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. +- f691c9b: **BREAKING**: Removed the ability to pass callback-form service factories through the `defaultServiceFactories` option of `createSpecializedBackend`. This is an immediate breaking change as usage of this function is expected to be very rare. + +### Patch Changes + +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- 617a7d2: Internal refactor that avoids the use of service factory options. +- b60db08: Fixing exporting of classes properly from new packages +- 18b96b1: The ability to install backend features in callback form (`() => BackendFeature`) has been deprecated. This typically means that you need to update the installed features to use the latest version of `@backstage/backend-plugin-api`. If the feature is from a third-party package, please reach out to the package maintainer to update it. +- a63c4b6: Fixing issue with `MiddlewareFactory` deprecation wrapping +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/cli-node@0.2.7 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.7.10-next.1 ### Patch Changes diff --git a/packages/backend-app-api/api-report-alpha.md b/packages/backend-app-api/api-report-alpha.md index 488feedf2c..8616eec29a 100644 --- a/packages/backend-app-api/api-report-alpha.md +++ b/packages/backend-app-api/api-report-alpha.md @@ -4,12 +4,14 @@ ```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', + 'singleton', + 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..dea309ebb0 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -39,14 +39,19 @@ 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 { ServiceFactoryOrFunction } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { transport } from 'winston'; 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', + 'singleton', + undefined +>; // @public (undocumented) export interface Backend { @@ -54,9 +59,16 @@ export interface Backend { add( feature: | BackendFeature + | Promise<{ + default: BackendFeature; + }>, + ): void; + // @deprecated (undocumented) + add( + feature: | (() => BackendFeature) | Promise<{ - default: BackendFeature | (() => BackendFeature); + default: () => BackendFeature; }>, ): void; // (undocumented) @@ -66,7 +78,12 @@ export interface Backend { } // @public @deprecated (undocumented) -export const cacheServiceFactory: () => ServiceFactory; +export const cacheServiceFactory: ServiceFactoryCompat< + CacheService, + 'plugin', + 'singleton', + undefined +>; // Warning: (ae-forgotten-export) The symbol "createConfigSecretEnumerator_2" needs to be exported by the entry point index.d.ts // @@ -91,13 +108,15 @@ export function createSpecializedBackend( // @public (undocumented) export interface CreateSpecializedBackendOptions { // (undocumented) - defaultServiceFactories: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactory[]; } // @public @deprecated (undocumented) -export const databaseServiceFactory: () => ServiceFactory< +export const databaseServiceFactory: ServiceFactoryCompat< DatabaseService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated @@ -116,9 +135,11 @@ export class DefaultRootHttpRouter implements RootHttpRouterService { export type DefaultRootHttpRouterOptions = DefaultRootHttpRouterOptions_2; // @public @deprecated (undocumented) -export const discoveryServiceFactory: () => ServiceFactory< +export const discoveryServiceFactory: ServiceFactoryCompat< DiscoveryService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // Warning: (ae-forgotten-export) The symbol "ExtendedHttpServer_2" needs to be exported by the entry point index.d.ts @@ -141,15 +162,19 @@ export class HostDiscovery implements DiscoveryService { } // @public @deprecated (undocumented) -export const httpAuthServiceFactory: () => ServiceFactory< +export const httpAuthServiceFactory: ServiceFactoryCompat< HttpAuthService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated -export const httpRouterServiceFactory: () => ServiceFactory< +export const httpRouterServiceFactory: ServiceFactoryCompat< HttpRouterService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // Warning: (ae-forgotten-export) The symbol "HttpServerCertificateOptions_2" needs to be exported by the entry point index.d.ts @@ -169,9 +194,12 @@ export type IdentityFactoryOptions = { }; // @public @deprecated (undocumented) -export const identityServiceFactory: ( - options?: IdentityFactoryOptions | undefined, -) => ServiceFactory; +export const identityServiceFactory: ServiceFactoryCompat< + IdentityService, + 'plugin', + 'singleton', + IdentityFactoryOptions +>; // Warning: (ae-forgotten-export) The symbol "LifecycleMiddlewareOptions_2" needs to be exported by the entry point index.d.ts // @@ -179,9 +207,11 @@ export const identityServiceFactory: ( export type LifecycleMiddlewareOptions = LifecycleMiddlewareOptions_2; // @public @deprecated -export const lifecycleServiceFactory: () => ServiceFactory< +export const lifecycleServiceFactory: ServiceFactoryCompat< LifecycleService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated @@ -195,9 +225,11 @@ export function loadBackendConfig(options: { }>; // @public @deprecated -export const loggerServiceFactory: () => ServiceFactory< +export const loggerServiceFactory: ServiceFactoryCompat< LoggerService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated (undocumented) @@ -222,9 +254,11 @@ export type MiddlewareFactoryErrorOptions = MiddlewareFactoryErrorOptions_2; export type MiddlewareFactoryOptions = MiddlewareFactoryOptions_2; // @public @deprecated (undocumented) -export const permissionsServiceFactory: () => ServiceFactory< +export const permissionsServiceFactory: ServiceFactoryCompat< PermissionsService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // Warning: (ae-forgotten-export) The symbol "readCorsOptions_2" needs to be exported by the entry point index.d.ts @@ -251,9 +285,12 @@ export interface RootConfigFactoryOptions { } // @public @deprecated (undocumented) -export const rootConfigServiceFactory: ( - options?: RootConfigFactoryOptions | undefined, -) => ServiceFactory; +export const rootConfigServiceFactory: ServiceFactoryCompat< + RootConfigService, + 'root', + 'singleton', + RootConfigFactoryOptions +>; // Warning: (ae-forgotten-export) The symbol "RootHttpRouterConfigureContext_2" needs to be exported by the entry point index.d.ts // @@ -266,44 +303,57 @@ export type RootHttpRouterConfigureContext = RootHttpRouterConfigureContext_2; export type RootHttpRouterFactoryOptions = RootHttpRouterFactoryOptions_2; // @public @deprecated (undocumented) -export const rootHttpRouterServiceFactory: ( +export const rootHttpRouterServiceFactory: (( options?: RootHttpRouterFactoryOptions_2 | undefined, -) => ServiceFactory; +) => ServiceFactory) & + ServiceFactory; // @public @deprecated -export const rootLifecycleServiceFactory: () => ServiceFactory< +export const rootLifecycleServiceFactory: ServiceFactoryCompat< RootLifecycleService, - 'root' + 'root', + 'singleton', + undefined >; // @public @deprecated -export const rootLoggerServiceFactory: () => ServiceFactory< +export const rootLoggerServiceFactory: ServiceFactoryCompat< RootLoggerService, - 'root' + 'root', + 'singleton', + undefined >; // @public @deprecated (undocumented) -export const schedulerServiceFactory: () => ServiceFactory< +export const schedulerServiceFactory: ServiceFactoryCompat< SchedulerService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated (undocumented) -export const tokenManagerServiceFactory: () => ServiceFactory< +export const tokenManagerServiceFactory: ServiceFactoryCompat< TokenManagerService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated (undocumented) -export const urlReaderServiceFactory: () => ServiceFactory< +export const urlReaderServiceFactory: ServiceFactoryCompat< UrlReaderService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated (undocumented) -export const userInfoServiceFactory: () => ServiceFactory< +export const userInfoServiceFactory: ServiceFactoryCompat< UserInfoService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated diff --git a/packages/backend-app-api/config.d.ts b/packages/backend-app-api/config.d.ts index a23bca447b..e94da62b77 100644 --- a/packages/backend-app-api/config.d.ts +++ b/packages/backend-app-api/config.d.ts @@ -287,6 +287,7 @@ export interface Config { } >; }; + packages?: 'all' | { include?: string[]; exclude?: string[] }; }; /** Discovery options. */ diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 4d3ffd874f..e809d1c2f0 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-app-api", - "version": "0.7.10-next.1", + "version": "0.8.1-next.2", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" @@ -79,7 +79,7 @@ "minimatch": "^9.0.0", "minimist": "^1.2.5", "morgan": "^1.10.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "node-forge": "^1.3.1", "path-to-regexp": "^6.2.1", "selfsigned": "^2.0.0", diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts index 3bbef5a4c0..6f60d65861 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts @@ -24,6 +24,7 @@ import { createBackendPlugin, createBackendModule, createExtensionPoint, + createBackendFeatureLoader, } from '@backstage/backend-plugin-api'; import { BackendInitializer } from './BackendInitializer'; @@ -105,6 +106,128 @@ describe('BackendInitializer', () => { expect(factory3).not.toHaveBeenCalled(); }); + it('should discover features from feature loader', async () => { + const ref1 = createServiceRef<{ x: number }>({ + id: '1', + scope: 'root', + }); + const ref2 = createServiceRef<{ x: number }>({ + id: '2', + scope: 'plugin', + }); + const factory1 = jest.fn(); + const factory2 = jest.fn(); + + const pluginInit = jest.fn(async () => {}); + const moduleInit = jest.fn(async () => {}); + + const init = new BackendInitializer(baseFactories); + init.add( + createBackendFeatureLoader({ + *loader() { + yield createServiceFactory({ + service: ref1, + deps: {}, + factory: factory1, + }); + yield createServiceFactory({ + service: ref2, + initialization: 'always', + deps: {}, + factory: factory2, + }); + yield createBackendPlugin({ + pluginId: 'test', + register(reg) { + reg.registerInit({ + deps: {}, + init: pluginInit, + }); + }, + }); + yield createBackendModule({ + pluginId: 'test', + moduleId: 'tester', + register(reg) { + reg.registerInit({ + deps: {}, + init: moduleInit, + }); + }, + }); + }, + }), + ); + await init.start(); + + expect(factory1).toHaveBeenCalled(); + expect(factory2).toHaveBeenCalled(); + expect(pluginInit).toHaveBeenCalled(); + expect(moduleInit).toHaveBeenCalled(); + }); + + it('should refuse to override already initialized services through loaded features', async () => { + const ref1 = createServiceRef<{ x: number }>({ + id: '1', + scope: 'root', + }); + + const init = new BackendInitializer([ + ...baseFactories, + createServiceFactory({ + service: ref1, + deps: {}, + factory: () => ({ x: 1 }), + }), + ]); + init.add( + createBackendFeatureLoader({ + deps: { service1: ref1 }, + *loader() { + yield createServiceFactory({ + service: ref1, + deps: {}, + factory: jest.fn(), + }); + }, + }), + ); + await expect(init.start()).rejects.toThrow( + 'Unable to set service factory with id 1, service has already been instantiated', + ); + }); + + it('should refuse feature loader that depends on a plugin scoped service', async () => { + const ref1 = createServiceRef<{ x: number }>({ + id: '1', + }); + + const init = new BackendInitializer([ + ...baseFactories, + createServiceFactory({ + service: ref1, + deps: {}, + factory: () => ({ x: 1 }), + }), + ]); + init.add( + createBackendFeatureLoader({ + // @ts-expect-error + deps: { service1: ref1 }, + *loader() { + yield createServiceFactory({ + service: ref1, + deps: {}, + factory: jest.fn(), + }); + }, + }), + ); + await expect(init.start()).rejects.toThrow( + /^Feature loaders can only depend on root scoped services, but 'service1' is scoped to 'plugin'. Offending loader is created at '.*'$/, + ); + }); + it('should initialize plugin scoped services with eager initialization', async () => { const ref1 = createServiceRef<{ x: number }>({ id: '1', diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index ddad94de14..c0da9eda62 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -25,8 +25,14 @@ import { } from '@backstage/backend-plugin-api'; import { ServiceOrExtensionPoint } from './types'; // Direct internal import to avoid duplication -// eslint-disable-next-line @backstage/no-forbidden-package-imports -import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import type { + InternalBackendFeature, + InternalBackendFeatureLoader, + InternalBackendRegistrations, +} from '../../../backend-plugin-api/src/wiring/types'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import type { InternalServiceFactory } from '../../../backend-plugin-api/src/services/system/types'; import { ForwardedError, ConflictError } from '@backstage/errors'; import { featureDiscoveryServiceRef } from '@backstage/backend-plugin-api/alpha'; import { DependencyGraph } from '../lib/DependencyGraph'; @@ -44,10 +50,11 @@ export interface BackendRegisterInit { export class BackendInitializer { #startPromise?: Promise; - #features = new Array(); + #registrations = new Array(); #extensionPoints = new Map(); #serviceRegistry: ServiceRegistry; #registeredFeatures = new Array>(); + #registeredFeatureLoaders = new Array(); constructor(defaultApiFactories: ServiceFactory[]) { this.#serviceRegistry = ServiceRegistry.create([...defaultApiFactories]); @@ -101,21 +108,12 @@ export class BackendInitializer { } #addFeature(feature: BackendFeature) { - if (feature.$$type !== '@backstage/BackendFeature') { - throw new Error( - `Failed to add feature, invalid type '${feature.$$type}'`, - ); - } - if (isServiceFactory(feature)) { this.#serviceRegistry.add(feature); - } else if (isInternalBackendFeature(feature)) { - if (feature.version !== 'v1') { - throw new Error( - `Failed to add feature, invalid version '${feature.version}'`, - ); - } - this.#features.push(feature); + } else if (isBackendFeatureLoader(feature)) { + this.#registeredFeatureLoaders.push(feature); + } else if (isBackendRegistrations(feature)) { + this.#registrations.push(feature); } else { throw new Error( `Failed to add feature, invalid feature ${JSON.stringify(feature)}`, @@ -170,14 +168,16 @@ export class BackendInitializer { this.#serviceRegistry.checkForCircularDeps(); } + await this.#applyBackendFeatureLoaders(this.#registeredFeatureLoaders); + // Initialize all root scoped services await this.#serviceRegistry.initializeEagerServicesWithScope('root'); const pluginInits = new Map(); const moduleInits = new Map>(); - // Enumerate all features - for (const feature of this.#features) { + // Enumerate all registrations + for (const feature of this.#registrations) { for (const r of feature.getRegistrations()) { const provides = new Set>(); @@ -205,7 +205,7 @@ export class BackendInitializer { consumes: new Set(Object.values(r.init.deps)), init: r.init, }); - } else { + } else if (r.type === 'module') { let modules = moduleInits.get(r.pluginId); if (!modules) { modules = new Map(); @@ -221,6 +221,8 @@ export class BackendInitializer { consumes: new Set(Object.values(r.init.deps)), init: r.init, }); + } else { + throw new Error(`Invalid registration type '${(r as any).type}'`); } } } @@ -383,16 +385,109 @@ export class BackendInitializer { throw new Error('Unexpected plugin lifecycle service implementation'); } + + async #applyBackendFeatureLoaders(loaders: InternalBackendFeatureLoader[]) { + for (const loader of loaders) { + const deps = new Map(); + const missingRefs = new Set(); + + for (const [name, ref] of Object.entries(loader.deps ?? {})) { + if (ref.scope !== 'root') { + throw new Error( + `Feature loaders can only depend on root scoped services, but '${name}' is scoped to '${ref.scope}'. Offending loader is ${loader.description}`, + ); + } + const impl = await this.#serviceRegistry.get( + ref as ServiceRef, + 'root', + ); + if (impl) { + deps.set(name, impl); + } else { + missingRefs.add(ref); + } + } + + if (missingRefs.size > 0) { + const missing = Array.from(missingRefs).join(', '); + throw new Error( + `No service available for the following ref(s): ${missing}, depended on by feature loader ${loader.description}`, + ); + } + + const result = await loader + .loader(Object.fromEntries(deps)) + .catch(error => { + throw new ForwardedError( + `Feature loader ${loader.description} failed`, + error, + ); + }); + + let didAddServiceFactory = false; + const newLoaders = new Array(); + + for await (const feature of result) { + if (isBackendFeatureLoader(feature)) { + newLoaders.push(feature); + } else { + didAddServiceFactory ||= isServiceFactory(feature); + this.#addFeature(feature); + } + } + + // Every time we add a new service factory we need to make sure that we don't have circular dependencies + if (didAddServiceFactory) { + this.#serviceRegistry.checkForCircularDeps(); + } + + // Apply loaders recursively, depth-first + if (newLoaders.length > 0) { + await this.#applyBackendFeatureLoaders(newLoaders); + } + } + } } -function isServiceFactory(feature: BackendFeature): feature is ServiceFactory { - return !!(feature as ServiceFactory).service; -} - -function isInternalBackendFeature( +function toInternalBackendFeature( feature: BackendFeature, -): feature is InternalBackendFeature { - return ( - typeof (feature as InternalBackendFeature).getRegistrations === 'function' - ); +): InternalBackendFeature { + if (feature.$$type !== '@backstage/BackendFeature') { + throw new Error(`Invalid BackendFeature, bad type '${feature.$$type}'`); + } + const internal = feature as InternalBackendFeature; + if (internal.version !== 'v1') { + throw new Error( + `Invalid BackendFeature, bad version '${internal.version}'`, + ); + } + return internal; +} + +function isServiceFactory( + feature: BackendFeature, +): feature is InternalServiceFactory { + const internal = toInternalBackendFeature(feature); + if (internal.featureType === 'service') { + return true; + } + // Backwards compatibility for v1 registrations that use duck typing + return 'service' in internal; +} + +function isBackendRegistrations( + feature: BackendFeature, +): feature is InternalBackendRegistrations { + const internal = toInternalBackendFeature(feature); + if (internal.featureType === 'registrations') { + return true; + } + // Backwards compatibility for v1 registrations that use duck typing + return 'getRegistrations' in internal; +} + +function isBackendFeatureLoader( + feature: BackendFeature, +): feature is InternalBackendFeatureLoader { + return toInternalBackendFeature(feature).featureType === 'loader'; } diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 6e20dd98e8..0abd5605ae 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -48,22 +48,34 @@ function toInternalServiceFactory( return f; } -const pluginMetadataServiceFactory = createServiceFactory( - (options?: { pluginId: string }) => ({ +function createPluginMetadataServiceFactory(pluginId: string) { + return createServiceFactory({ service: coreServices.pluginMetadata, deps: {}, - factory: async () => ({ getId: () => options?.pluginId! }), - }), -); + factory: async () => ({ getId: () => pluginId }), + }); +} export class ServiceRegistry { static create(factories: Array): ServiceRegistry { - const registry = new ServiceRegistry(factories); + const factoryMap = new Map(); + for (const factory of factories) { + if (factory.service.multiton) { + const existing = factoryMap.get(factory.service.id) ?? []; + factoryMap.set( + factory.service.id, + existing.concat(toInternalServiceFactory(factory)), + ); + } else { + factoryMap.set(factory.service.id, [toInternalServiceFactory(factory)]); + } + } + const registry = new ServiceRegistry(factoryMap); registry.checkForCircularDeps(); return registry; } - readonly #providedFactories: Map; + readonly #providedFactories: Map; readonly #loadedDefaultFactories: Map< Function, Promise @@ -82,10 +94,8 @@ export class ServiceRegistry { readonly #addedFactoryIds = new Set(); readonly #instantiatedFactories = new Set(); - private constructor(factories: Array) { - this.#providedFactories = new Map( - factories.map(sf => [sf.service.id, toInternalServiceFactory(sf)]), - ); + private constructor(factories: Map) { + this.#providedFactories = factories; this.#loadedDefaultFactories = new Map(); this.#implementations = new Map(); } @@ -93,17 +103,17 @@ export class ServiceRegistry { #resolveFactory( ref: ServiceRef, pluginId: string, - ): Promise | undefined { + ): Promise | undefined { // Special case handling of the plugin metadata service, generating a custom factory for it each time if (ref.id === coreServices.pluginMetadata.id) { - return Promise.resolve( - toInternalServiceFactory(pluginMetadataServiceFactory({ pluginId })), - ); + return Promise.resolve([ + toInternalServiceFactory(createPluginMetadataServiceFactory(pluginId)), + ]); } let resolvedFactory: - | Promise - | InternalServiceFactory + | Promise + | InternalServiceFactory[] | undefined = this.#providedFactories.get(ref.id); const { __defaultFactory: defaultFactory } = ref as InternalServiceRef; if (!resolvedFactory && !defaultFactory) { @@ -120,15 +130,18 @@ export class ServiceRegistry { ); this.#loadedDefaultFactories.set(defaultFactory!, loadedFactory); } - resolvedFactory = loadedFactory.catch(error => { - throw new Error( - `Failed to instantiate service '${ - ref.id - }' because the default factory loader threw an error, ${stringifyError( - error, - )}`, - ); - }); + resolvedFactory = loadedFactory.then( + factory => [factory], + error => { + throw new Error( + `Failed to instantiate service '${ + ref.id + }' because the default factory loader threw an error, ${stringifyError( + error, + )}`, + ); + }, + ); } return Promise.resolve(resolvedFactory); @@ -142,6 +155,9 @@ export class ServiceRegistry { if (this.#providedFactories.get(ref.id)) { return false; } + if (ref.multiton) { + return false; + } return !(ref as InternalServiceRef).__defaultFactory; }); @@ -156,13 +172,13 @@ export class ServiceRegistry { checkForCircularDeps(): void { const graph = DependencyGraph.fromIterable( - Array.from(this.#providedFactories).map( - ([serviceId, serviceFactory]) => ({ - value: serviceId, - provides: [serviceId], - consumes: Object.values(serviceFactory.deps).map(d => d.id), - }), - ), + Array.from(this.#providedFactories).map(([serviceId, factories]) => ({ + value: serviceId, + provides: [serviceId], + consumes: factories.flatMap(factory => + Object.values(factory.deps).map(d => d.id), + ), + })), ); const circularDependencies = Array.from(graph.detectCircularDependencies()); @@ -183,27 +199,36 @@ export class ServiceRegistry { ); } - if (this.#addedFactoryIds.has(factoryId)) { - throw new Error( - `Duplicate service implementations provided for ${factoryId}`, - ); - } - if (this.#instantiatedFactories.has(factoryId)) { throw new Error( `Unable to set service factory with id ${factoryId}, service has already been instantiated`, ); } - this.#addedFactoryIds.add(factoryId); - this.#providedFactories.set(factoryId, toInternalServiceFactory(factory)); + if (factory.service.multiton) { + const newFactories = ( + this.#providedFactories.get(factoryId) ?? [] + ).concat(toInternalServiceFactory(factory)); + this.#providedFactories.set(factoryId, newFactories); + } else { + if (this.#addedFactoryIds.has(factoryId)) { + throw new Error( + `Duplicate service implementations provided for ${factoryId}`, + ); + } + + this.#addedFactoryIds.add(factoryId); + this.#providedFactories.set(factoryId, [ + toInternalServiceFactory(factory), + ]); + } } async initializeEagerServicesWithScope( scope: 'root' | 'plugin', pluginId: string = 'root', ) { - for (const factory of this.#providedFactories.values()) { + for (const [factory] of this.#providedFactories.values()) { if (factory.service.scope === scope) { // Root-scoped services are eager by default, plugin-scoped are lazy by default if (scope === 'root' && factory.initialization !== 'lazy') { @@ -215,88 +240,112 @@ export class ServiceRegistry { } } - get(ref: ServiceRef, pluginId: string): Promise | undefined { + get( + ref: ServiceRef, + pluginId: string, + ): Promise | undefined { this.#instantiatedFactories.add(ref.id); - return this.#resolveFactory(ref, pluginId)?.then(factory => { - if (factory.service.scope === 'root') { - let existing = this.#rootServiceImplementations.get(factory); - if (!existing) { - this.#checkForMissingDeps(factory, pluginId); - const rootDeps = new Array>(); + const resolvedFactory = this.#resolveFactory(ref, pluginId); - for (const [name, serviceRef] of Object.entries(factory.deps)) { - if (serviceRef.scope !== 'root') { - throw new Error( - `Failed to instantiate 'root' scoped service '${ref.id}' because it depends on '${serviceRef.scope}' scoped service '${serviceRef.id}'.`, - ); + if (!resolvedFactory) { + return ref.multiton + ? (Promise.resolve([]) as + | Promise + | undefined) + : undefined; + } + + return resolvedFactory + .then(factories => { + return Promise.all( + factories.map(factory => { + if (factory.service.scope === 'root') { + let existing = this.#rootServiceImplementations.get(factory); + if (!existing) { + this.#checkForMissingDeps(factory, pluginId); + const rootDeps = new Array< + Promise<[name: string, impl: unknown]> + >(); + + for (const [name, serviceRef] of Object.entries(factory.deps)) { + if (serviceRef.scope !== 'root') { + throw new Error( + `Failed to instantiate 'root' scoped service '${ref.id}' because it depends on '${serviceRef.scope}' scoped service '${serviceRef.id}'.`, + ); + } + const target = this.get(serviceRef, pluginId)!; + rootDeps.push(target.then(impl => [name, impl])); + } + + existing = Promise.all(rootDeps).then(entries => + factory.factory(Object.fromEntries(entries), undefined), + ); + this.#rootServiceImplementations.set(factory, existing); + } + return existing as Promise; } - const target = this.get(serviceRef, pluginId)!; - rootDeps.push(target.then(impl => [name, impl])); - } - existing = Promise.all(rootDeps).then(entries => - factory.factory(Object.fromEntries(entries), undefined), - ); - this.#rootServiceImplementations.set(factory, existing); - } - return existing as Promise; - } + let implementation = this.#implementations.get(factory); + if (!implementation) { + this.#checkForMissingDeps(factory, pluginId); + const rootDeps = new Array< + Promise<[name: string, impl: unknown]> + >(); - let implementation = this.#implementations.get(factory); - if (!implementation) { - this.#checkForMissingDeps(factory, pluginId); - const rootDeps = new Array>(); + for (const [name, serviceRef] of Object.entries(factory.deps)) { + if (serviceRef.scope === 'root') { + const target = this.get(serviceRef, pluginId)!; + rootDeps.push(target.then(impl => [name, impl])); + } + } - for (const [name, serviceRef] of Object.entries(factory.deps)) { - if (serviceRef.scope === 'root') { - const target = this.get(serviceRef, pluginId)!; - rootDeps.push(target.then(impl => [name, impl])); - } - } + implementation = { + context: Promise.all(rootDeps) + .then(entries => + factory.createRootContext?.(Object.fromEntries(entries)), + ) + .catch(error => { + const cause = stringifyError(error); + throw new Error( + `Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`, + ); + }), + byPlugin: new Map(), + }; - implementation = { - context: Promise.all(rootDeps) - .then(entries => - factory.createRootContext?.(Object.fromEntries(entries)), - ) - .catch(error => { - const cause = stringifyError(error); - throw new Error( - `Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`, - ); - }), - byPlugin: new Map(), - }; + this.#implementations.set(factory, implementation); + } - this.#implementations.set(factory, implementation); - } + let result = implementation.byPlugin.get(pluginId) as Promise; + if (!result) { + const allDeps = new Array< + Promise<[name: string, impl: unknown]> + >(); - let result = implementation.byPlugin.get(pluginId) as Promise; - if (!result) { - const allDeps = new Array>(); + for (const [name, serviceRef] of Object.entries(factory.deps)) { + const target = this.get(serviceRef, pluginId)!; + allDeps.push(target.then(impl => [name, impl])); + } - for (const [name, serviceRef] of Object.entries(factory.deps)) { - const target = this.get(serviceRef, pluginId)!; - allDeps.push(target.then(impl => [name, impl])); - } - - result = implementation.context - .then(context => - Promise.all(allDeps).then(entries => - factory.factory(Object.fromEntries(entries), context), - ), - ) - .catch(error => { - const cause = stringifyError(error); - throw new Error( - `Failed to instantiate service '${ref.id}' for '${pluginId}' because the factory function threw an error, ${cause}`, - ); - }); - implementation.byPlugin.set(pluginId, result); - } - - return result; - }); + result = implementation.context + .then(context => + Promise.all(allDeps).then(entries => + factory.factory(Object.fromEntries(entries), context), + ), + ) + .catch(error => { + const cause = stringifyError(error); + throw new Error( + `Failed to instantiate service '${ref.id}' for '${pluginId}' because the factory function threw an error, ${cause}`, + ); + }); + implementation.byPlugin.set(pluginId, result); + } + return result; + }), + ); + }) + .then(results => (ref.multiton ? results : results[0])); } } diff --git a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts index f5c4d8b152..fd449be541 100644 --- a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts +++ b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts @@ -24,13 +24,9 @@ import { Backend, CreateSpecializedBackendOptions } from './types'; export function createSpecializedBackend( options: CreateSpecializedBackendOptions, ): Backend { - const services = options.defaultServiceFactories.map(sf => - typeof sf === 'function' ? sf() : sf, - ); - const exists = new Set(); const duplicates = new Set(); - for (const { service } of services) { + for (const { service } of options.defaultServiceFactories) { if (exists.has(service.id)) { duplicates.add(service.id); } else { @@ -47,5 +43,5 @@ export function createSpecializedBackend( ); } - return new BackstageBackend(services); + return new BackstageBackend(options.defaultServiceFactories); } diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index 027b2bf254..075eb58b3f 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -18,18 +18,25 @@ import { BackendFeature, ExtensionPoint, ServiceRef, - ServiceFactoryOrFunction, + ServiceFactory, } from '@backstage/backend-plugin-api'; /** * @public */ export interface Backend { + add(feature: BackendFeature | Promise<{ default: BackendFeature }>): void; + /** + * @deprecated The ability to add features defined as a callback is being + * removed. Please update the installed feature to no longer be defined as a + * callback, typically this means updating it to use the latest version of + * `@backstage/backend-plugin-api`. If the feature is from a third-party + * package, please reach out to the package maintainer to update it. + */ add( feature: - | BackendFeature | (() => BackendFeature) - | Promise<{ default: BackendFeature | (() => BackendFeature) }>, + | Promise<{ default: () => BackendFeature }>, ): void; start(): Promise; stop(): Promise; @@ -39,7 +46,7 @@ export interface Backend { * @public */ export interface CreateSpecializedBackendOptions { - defaultServiceFactories: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactory[]; } /** diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index d144d461b8..5eadae4c0f 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,87 @@ # @backstage/backend-common +## 0.23.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.23.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 0.23.4-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- 7e13b7a: The remaining exports in the package have now been deprecated: + + - `cacheToPluginCacheManager` + - `createLegacyAuthAdapters` + - `LegacyCreateRouter` + - `legacyPlugin` + - `loggerToWinstonLogger` + - `makeLegacyPlugin` + + Users of these export should fully [migrate to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating). + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## 0.23.3 + +### Patch Changes + +- 8c09c97: Deprecate legacy status check factory, handler and types. +- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware +- c964a3d: Add dependencies that are needed by cross-imports from backend-defaults +- b60db08: Fixing exporting of classes properly from new packages +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.23.3-next.1 ### Patch Changes diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 52b661bcaf..23ed13b62c 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -129,7 +129,7 @@ export class CacheManager extends CacheManager_2 {} // @public @deprecated (undocumented) export type CacheManagerOptions = CacheManagerOptions_2; -// @public +// @public @deprecated export function cacheToPluginCacheManager(cache: CacheService): { getClient(options?: CacheServiceOptions): CacheService; }; @@ -142,7 +142,7 @@ export interface ContainerRunner { runContainer(opts: RunContainerOptions): Promise; } -// @public +// @public @deprecated export function createLegacyAuthAdapters< TOptions extends { auth?: AuthService; @@ -401,10 +401,10 @@ export type KubernetesContainerRunnerOptions = { timeoutMs?: number; }; -// @public (undocumented) +// @public @deprecated (undocumented) export type LegacyCreateRouter = (deps: TEnv) => Promise; -// @public +// @public @deprecated export const legacyPlugin: ( name: string, createRouterImport: Promise<{ @@ -447,13 +447,13 @@ export function loadBackendConfig(options: { watch?: boolean; }): Promise; -// @public (undocumented) +// @public @deprecated (undocumented) export function loggerToWinstonLogger( logger: LoggerService, opts?: TransportStreamOptions, ): Logger; -// @public +// @public @deprecated export function makeLegacyPlugin< TEnv extends Record, TEnvTransforms extends { diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index f23f0d2ce9..ccf44fba0f 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-common", - "version": "0.23.3-next.1", + "version": "0.23.4-next.2", "description": "Common functionality library for Backstage backends", "backstage": { "role": "node-library" @@ -102,7 +102,7 @@ "minimist": "^1.2.5", "morgan": "^1.10.0", "mysql2": "^3.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "node-forge": "^1.3.1", "p-limit": "^3.1.0", "path-to-regexp": "^6.2.1", diff --git a/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts b/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts index 0f591eac6c..15cd881649 100644 --- a/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts +++ b/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts @@ -292,6 +292,7 @@ export class UserInfoCompat implements UserInfoService { /** * An adapter that ensures presence of the auth and/or httpAuth services. * @public + * @deprecated Migrate to use the new backend system and auth services instead. */ export function createLegacyAuthAdapters< TOptions extends { diff --git a/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts b/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts index 2654934804..2ae55b016f 100644 --- a/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts +++ b/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts @@ -24,6 +24,7 @@ import { * old-backend plugin cache manager. * * @public + * @deprecated Migrate to use the new CacheService instead. */ export function cacheToPluginCacheManager(cache: CacheService): { getClient(options?: CacheServiceOptions): CacheService; diff --git a/packages/backend-common/src/compat/legacy/legacy.ts b/packages/backend-common/src/compat/legacy/legacy.ts index 57220a8430..c779daacd2 100644 --- a/packages/backend-common/src/compat/legacy/legacy.ts +++ b/packages/backend-common/src/compat/legacy/legacy.ts @@ -27,6 +27,7 @@ import { TokenManager } from '../../deprecated'; /** * @public + * @deprecated Fully use the new backend system instead. */ export type LegacyCreateRouter = (deps: TEnv) => Promise; @@ -69,6 +70,7 @@ function wrapTokenManager(tokenManager: TokenManager, auth: AuthService) { * Creates a new custom plugin compatibility wrapper. * * @public + * @deprecated Fully use the new backend system instead. * @remarks * * Usually you can use {@link legacyPlugin} directly instead, but you might @@ -128,6 +130,7 @@ export function makeLegacyPlugin< * register it with the http router based on the plugin id. * * @public + * @deprecated Fully use the new backend system instead. * @remarks * * This is intended to be used by plugin authors to ease the transition to the diff --git a/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts b/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts index 4ba88358d2..83871f48e3 100644 --- a/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts +++ b/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts @@ -53,7 +53,10 @@ class BackstageLoggerTransport extends Transport { } } -/** @public */ +/** + * @public + * @deprecated Migrate to use the new LoggerService instead. + */ export function loggerToWinstonLogger( logger: LoggerService, opts?: TransportStreamOptions, diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index a9b20bfbea..44b0a6b9b0 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/backend-defaults +## 0.4.2-next.2 + +### Patch Changes + +- 0d16b52: Add access restrictions to the JWKS external access method config schema +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- ba9abf4: The `SchedulerService` now allows tasks with `frequency: { trigger: 'manual' }`. This means that the task will not be scheduled, but rather run only when manually triggered with `SchedulerService.triggerTask`. +- 7c5f3b0: Update the `UrlReader` service to depends on multiple instances of `UrlReaderFactoryProvider` service. +- 1d5f298: Avoid excessive numbers of error listeners on cache clients +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-app-api@0.8.1-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-app-api@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.4.2-next.0 + +### Patch Changes + +- 4e79d19: The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`. +- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. +- 8e967da: Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## 0.4.0 + +### Minor Changes + +- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. + +### Patch Changes + +- 53ced70: Added a new Root Health Service which adds new endpoints for health checks. +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- 419f387: Refactor of `rootHttpRouterServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. +- cb14a05: Repack the package to fix issues with typescript with named exports +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- e28af58: Refactor of `rootConfigServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.3.4-next.1 ### Patch Changes diff --git a/packages/backend-defaults/api-report-auth.md b/packages/backend-defaults/api-report-auth.md index d64ce5bc2a..5ceca7f72e 100644 --- a/packages/backend-defaults/api-report-auth.md +++ b/packages/backend-defaults/api-report-auth.md @@ -4,10 +4,15 @@ ```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', + 'singleton', + 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..e8b6f075ab 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,12 @@ export type CacheManagerOptions = { }; // @public -export const cacheServiceFactory: () => ServiceFactory; +export const cacheServiceFactory: ServiceFactoryCompat< + CacheService, + 'plugin', + 'singleton', + 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..8d204db025 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,11 @@ export type DatabaseManagerOptions = { }; // @public -export const databaseServiceFactory: () => ServiceFactory< +export const databaseServiceFactory: ServiceFactoryCompat< DatabaseService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public @deprecated diff --git a/packages/backend-defaults/api-report-discovery.md b/packages/backend-defaults/api-report-discovery.md index b434dab6fc..1b19a42aa5 100644 --- a/packages/backend-defaults/api-report-discovery.md +++ b/packages/backend-defaults/api-report-discovery.md @@ -5,12 +5,14 @@ ```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', + 'singleton', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-httpAuth.md b/packages/backend-defaults/api-report-httpAuth.md index 6ffe3d6539..a65a6e157d 100644 --- a/packages/backend-defaults/api-report-httpAuth.md +++ b/packages/backend-defaults/api-report-httpAuth.md @@ -4,12 +4,14 @@ ```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', + 'singleton', + 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..300e75a44d 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,11 @@ export function createLifecycleMiddleware( ): RequestHandler; // @public -export const httpRouterServiceFactory: () => ServiceFactory< +export const httpRouterServiceFactory: ServiceFactoryCompat< HttpRouterService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-lifecycle.md b/packages/backend-defaults/api-report-lifecycle.md index 4233584664..54ffb77fed 100644 --- a/packages/backend-defaults/api-report-lifecycle.md +++ b/packages/backend-defaults/api-report-lifecycle.md @@ -4,12 +4,14 @@ ```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', + 'singleton', + 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..40ca4e21b4 100644 --- a/packages/backend-defaults/api-report-logger.md +++ b/packages/backend-defaults/api-report-logger.md @@ -4,12 +4,14 @@ ```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', + 'singleton', + 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..eea11ed7c9 100644 --- a/packages/backend-defaults/api-report-permissions.md +++ b/packages/backend-defaults/api-report-permissions.md @@ -4,12 +4,14 @@ ```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', + 'singleton', + 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..2935ad1128 100644 --- a/packages/backend-defaults/api-report-rootConfig.md +++ b/packages/backend-defaults/api-report-rootConfig.md @@ -26,9 +26,10 @@ export interface RootConfigFactoryOptions { } // @public (undocumented) -export const rootConfigServiceFactory: ( - options?: RootConfigFactoryOptions | undefined, -) => ServiceFactory; +export const rootConfigServiceFactory: (( + options?: RootConfigFactoryOptions, +) => ServiceFactory) & + ServiceFactory; // (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..c7580cacd6 100644 --- a/packages/backend-defaults/api-report-rootHealth.md +++ b/packages/backend-defaults/api-report-rootHealth.md @@ -4,12 +4,14 @@ ```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', + 'singleton', + 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..3686f25a12 100644 --- a/packages/backend-defaults/api-report-rootHttpRouter.md +++ b/packages/backend-defaults/api-report-rootHttpRouter.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// /// import { Config } from '@backstage/config'; @@ -17,10 +18,17 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import { RequestHandler } from 'express'; import { RequestListener } from 'http'; import { RootConfigService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; import { RootHttpRouterService } from '@backstage/backend-plugin-api'; +import { Router } from 'express'; import type { Server } from 'node:http'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +// @public (undocumented) +export function createHealthRouter(options: { + health: RootHealthService; +}): Router; + // @public export function createHttpServer( listener: RequestListener, @@ -141,9 +149,10 @@ export type RootHttpRouterFactoryOptions = { }; // @public (undocumented) -export const rootHttpRouterServiceFactory: ( - options?: RootHttpRouterFactoryOptions | undefined, -) => ServiceFactory; +export const rootHttpRouterServiceFactory: (( + options?: RootHttpRouterFactoryOptions, +) => ServiceFactory) & + ServiceFactory; // (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..e522471d04 100644 --- a/packages/backend-defaults/api-report-rootLifecycle.md +++ b/packages/backend-defaults/api-report-rootLifecycle.md @@ -4,12 +4,14 @@ ```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', + 'singleton', + 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..3878420192 100644 --- a/packages/backend-defaults/api-report-rootLogger.md +++ b/packages/backend-defaults/api-report-rootLogger.md @@ -7,13 +7,15 @@ 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', + 'singleton', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-scheduler.md b/packages/backend-defaults/api-report-scheduler.md index 58991ddca3..9953518e09 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,11 @@ export class DefaultSchedulerService { } // @public -export const schedulerServiceFactory: () => ServiceFactory< +export const schedulerServiceFactory: ServiceFactoryCompat< SchedulerService, - 'plugin' + 'plugin', + 'singleton', + 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..f561c2cbf5 100644 --- a/packages/backend-defaults/api-report-urlReader.md +++ b/packages/backend-defaults/api-report-urlReader.md @@ -21,7 +21,8 @@ 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 { ServiceRef } 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'; @@ -413,6 +414,13 @@ export type ReadUrlResponseFactoryFromStreamOptions = { lastModifiedAt?: Date; }; +// @public +export const urlReaderFactoriesServiceRef: ServiceRef< + ReaderFactory, + 'plugin', + 'multiton' +>; + // @public export type UrlReaderPredicateTuple = { predicate: (url: URL) => boolean; @@ -426,9 +434,11 @@ export class UrlReaders { } // @public -export const urlReaderServiceFactory: () => ServiceFactory< +export const urlReaderServiceFactory: ServiceFactoryCompat< UrlReaderService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-userInfo.md b/packages/backend-defaults/api-report-userInfo.md index d11fb69718..27f73d06e1 100644 --- a/packages/backend-defaults/api-report-userInfo.md +++ b/packages/backend-defaults/api-report-userInfo.md @@ -3,13 +3,15 @@ > 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', + 'singleton', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/config.d.ts b/packages/backend-defaults/config.d.ts index ab1e443fc2..1c784bce0c 100644 --- a/packages/backend-defaults/config.d.ts +++ b/packages/backend-defaults/config.d.ts @@ -287,6 +287,46 @@ export interface Config { */ subjectPrefix?: string; }; + /** + * Restricts what types of access that are permitted for this access + * method. If no access restrictions are given, it'll have unlimited + * access. This access restriction applies for the framework level; + * individual plugins may have their own access control mechanisms + * on top of this. + */ + accessRestrictions?: Array<{ + /** + * Permit access to make requests to this plugin. + * + * Can be further refined by setting additional fields below. + */ + plugin: string; + /** + * If given, this method is limited to only performing actions + * with these named permissions in this plugin. + * + * Note that this only applies where permissions checks are + * enabled in the first place. Endpoints that are not protected by + * the permissions system at all, are not affected by this + * setting. + */ + permission?: string | Array; + /** + * If given, this method is limited to only performing actions + * whose permissions have these attributes. + * + * Note that this only applies where permissions checks are + * enabled in the first place. Endpoints that are not protected by + * the permissions system at all, are not affected by this + * setting. + */ + permissionAttribute?: { + /** + * One of more of 'create', 'read', 'update', or 'delete'. + */ + action?: string | Array; + }; + }>; } >; }; diff --git a/packages/backend-defaults/migrations/scheduler/20240712211735_nullable_next_run.js b/packages/backend-defaults/migrations/scheduler/20240712211735_nullable_next_run.js new file mode 100644 index 0000000000..efbef1c76f --- /dev/null +++ b/packages/backend-defaults/migrations/scheduler/20240712211735_nullable_next_run.js @@ -0,0 +1,41 @@ +/* + * 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. + */ + +// @ts-check + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = async function up(knex) { + await knex.schema.alterTable('backstage_backend_tasks__tasks', table => { + table.setNullable('next_run_start_at'); + }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = async function down(knex) { + await knex + .delete() + .from('backstage_backend_tasks__tasks') + .where({ next_run_start_at: null }); + await knex.schema.alterTable('backstage_backend_tasks__tasks', table => { + table.dropNullable('next_run_start_at'); + }); +}; diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 0606d942ff..cef9641de6 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.3.4-next.1", + "version": "0.4.2-next.2", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" @@ -165,7 +165,7 @@ "minimist": "^1.2.5", "morgan": "^1.10.0", "mysql2": "^3.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "node-forge": "^1.3.1", "p-limit": "^3.1.0", "path-to-regexp": "^6.2.1", diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index e3195748a6..47fa09da49 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -40,26 +40,26 @@ import { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo'; import { eventsServiceFactory } from '@backstage/plugin-events-node'; export const defaultServiceFactories = [ - authServiceFactory(), - cacheServiceFactory(), - rootConfigServiceFactory(), - databaseServiceFactory(), - discoveryServiceFactory(), - httpAuthServiceFactory(), - httpRouterServiceFactory(), - identityServiceFactory(), - lifecycleServiceFactory(), - loggerServiceFactory(), - permissionsServiceFactory(), - rootHealthServiceFactory(), - rootHttpRouterServiceFactory(), - rootLifecycleServiceFactory(), - rootLoggerServiceFactory(), - schedulerServiceFactory(), - tokenManagerServiceFactory(), - userInfoServiceFactory(), - urlReaderServiceFactory(), - eventsServiceFactory(), + authServiceFactory, + cacheServiceFactory, + rootConfigServiceFactory, + databaseServiceFactory, + discoveryServiceFactory, + httpAuthServiceFactory, + httpRouterServiceFactory, + identityServiceFactory, + lifecycleServiceFactory, + loggerServiceFactory, + permissionsServiceFactory, + rootHealthServiceFactory, + rootHttpRouterServiceFactory, + rootLifecycleServiceFactory, + rootLoggerServiceFactory, + schedulerServiceFactory, + tokenManagerServiceFactory, + userInfoServiceFactory, + urlReaderServiceFactory, + eventsServiceFactory, ]; /** diff --git a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts index de89efa351..f9ef4c9762 100644 --- a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts @@ -17,7 +17,7 @@ import { ServiceFactoryTester, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { tokenManagerServiceFactory } from '@backstage/backend-app-api'; import { authServiceFactory } from './authServiceFactory'; @@ -68,7 +68,7 @@ const mockDeps = [ ]; describe('authServiceFactory', () => { - setupRequestMockHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.useRealTimers(); diff --git a/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts index 559107c59c..39b01c46b6 100644 --- a/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts @@ -19,7 +19,7 @@ import { ExternalTokenHandler } from './ExternalTokenHandler'; import { TokenHandler } from './types'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { randomBytes } from 'crypto'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; @@ -81,7 +81,7 @@ class FakeTokenFactory { describe('ExternalTokenHandler', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); it('skips over inner handlers that do not match, and applies plugin restrictions', async () => { const handler1: TokenHandler = { diff --git a/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts b/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts index 56930e4480..321e1823aa 100644 --- a/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; @@ -81,7 +81,7 @@ describe('JWKSHandler', () => { let mockSubject: string; const keyDurationSeconds = 5; - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { mockSubject = 'test_subject'; diff --git a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts index 76bafb2a8f..e85ec8db63 100644 --- a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts @@ -18,7 +18,7 @@ import { JsonObject } from '@backstage/types'; import { UserTokenHandler } from './UserTokenHandler'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -64,7 +64,7 @@ async function createToken(options: { describe('UserTokenHandler', () => { let userTokenHandler: UserTokenHandler; - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.useRealTimers(); diff --git a/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts index 89fabfe977..873bcf9648 100644 --- a/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts +++ b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts @@ -111,23 +111,10 @@ export class CacheManager { return { getClient: (defaultOptions = {}) => { const clientFactory = (options: CacheServiceOptions) => { - const concreteClient = this.getClientWithTtl( + return this.getClientWithTtl( pluginId, options.defaultTtl ?? this.defaultTtl, ); - - // Always provide an error handler to avoid stopping the process. - concreteClient.on('error', (err: Error) => { - // In all cases, just log the error. - this.logger?.error('Failed to create cache client', err); - - // Invoke any custom error handler if provided. - if (typeof this.errorHandler === 'function') { - this.errorHandler(err); - } - }); - - return concreteClient; }; return new DefaultCacheClient( @@ -149,11 +136,17 @@ export class CacheManager { return (pluginId, defaultTtl) => { if (!store) { store = new KeyvRedis(this.connection); + // Always provide an error handler to avoid stopping the process + store.on('error', (err: Error) => { + this.logger?.error('Failed to create redis cache client', err); + this.errorHandler?.(err); + }); } return new Keyv({ namespace: pluginId, ttl: defaultTtl, store, + emitErrors: false, useRedisSets: this.useRedisSets, }); }; @@ -165,10 +158,16 @@ export class CacheManager { return (pluginId, defaultTtl) => { if (!store) { store = new KeyvMemcache(this.connection); + // Always provide an error handler to avoid stopping the process + store.on('error', (err: Error) => { + this.logger?.error('Failed to create memcache cache client', err); + this.errorHandler?.(err); + }); } return new Keyv({ namespace: pluginId, ttl: defaultTtl, + emitErrors: false, store, }); }; @@ -180,6 +179,7 @@ export class CacheManager { new Keyv({ namespace: pluginId, ttl: defaultTtl, + emitErrors: false, store, }); } diff --git a/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts index 5752a9c634..63a7353241 100644 --- a/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts @@ -45,11 +45,10 @@ export interface RootConfigFactoryOptions { watch?: boolean; } -/** - * @public - */ -export const rootConfigServiceFactory = createServiceFactory( - (options?: RootConfigFactoryOptions) => ({ +export const rootConfigServiceFactoryWithOptions = ( + options?: RootConfigFactoryOptions, +) => + createServiceFactory({ service: coreServices.rootConfig, deps: {}, async factory() { @@ -61,5 +60,12 @@ export const rootConfigServiceFactory = createServiceFactory( console.log(`Loading config from ${source}`); return await ConfigSources.toConfig(source); }, - }), + })(); + +/** + * @public + */ +export const rootConfigServiceFactory = Object.assign( + rootConfigServiceFactoryWithOptions, + rootConfigServiceFactoryWithOptions(), ); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts index 13691ede28..3772ab0fab 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -1,5 +1,3 @@ -import { RootHealthService } from '@backstage/backend-plugin-api'; - /* * Copyright 2024 The Backstage Authors * @@ -16,14 +14,18 @@ import { RootHealthService } from '@backstage/backend-plugin-api'; * limitations under the License. */ +import { RootHealthService } from '@backstage/backend-plugin-api'; import Router from 'express-promise-router'; import { Request, Response } from 'express'; +/** + * @public + */ export function createHealthRouter(options: { health: RootHealthService }) { const router = Router(); router.get( - '.backstage/health/v1/readiness', + '/.backstage/health/v1/readiness', async (_request: Request, response: Response) => { const { status, payload } = await options.health.getReadiness(); response.status(status).json(payload); @@ -31,7 +33,7 @@ export function createHealthRouter(options: { health: RootHealthService }) { ); router.get( - '.backstage/health/v1/liveness', + '/.backstage/health/v1/liveness', async (_request: Request, response: Response) => { const { status, payload } = await options.health.getLiveness(); response.status(status).json(payload); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts index 9c2d96dab2..e9aee8a0e0 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts @@ -18,6 +18,7 @@ export { DefaultRootHttpRouter, type DefaultRootHttpRouterOptions, } from './DefaultRootHttpRouter'; +export { createHealthRouter } from './createHealthRouter'; export * from './http'; export { rootHttpRouterServiceFactory, diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts new file mode 100644 index 0000000000..dea0159dff --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ServiceFactoryTester, + mockServices, +} from '@backstage/backend-test-utils'; +import { Express } from 'express'; +import request from 'supertest'; +import { rootHttpRouterServiceFactory } from './rootHttpRouterServiceFactory'; +import { coreServices } from '@backstage/backend-plugin-api'; + +describe('rootHttpRouterServiceFactory', () => { + it('should make the health endpoints available', async () => { + let app: Express | undefined = undefined; + + const tester = ServiceFactoryTester.from( + rootHttpRouterServiceFactory({ + configure(options) { + options.applyDefaults(); + app = options.app; + }, + }), + { + dependencies: [ + mockServices.rootConfig.factory({ + data: { + app: { baseUrl: 'http://localhost' }, + backend: { + baseUrl: 'http://localhost', + listen: { host: '', port: 0 }, + }, + }, + }), + ], + }, + ); + + // Trigger creation of the http service, accessing the app instance through the configure callback + await tester.getSubject(); + + await request(app!) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + await request(app!).get('/.backstage/health/v1/readiness').expect(503, { + message: 'Backend has not started yet', + status: 'error', + }); + + const lifecycle = await tester.getService(coreServices.rootLifecycle); + + await (lifecycle as any).startup(); // Trigger startup by calling the private startup method + + await request(app!).get('/.backstage/health/v1/readiness').expect(200, { + status: 'ok', + }); + + expect('test').toBe('test'); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index 22f5c2f310..c3a97737e4 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -69,9 +69,10 @@ function defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) { applyDefaults(); } -/** @public */ -export const rootHttpRouterServiceFactory = createServiceFactory( - (options?: RootHttpRouterFactoryOptions) => ({ +const rootHttpRouterServiceFactoryWithOptions = ( + options?: RootHttpRouterFactoryOptions, +) => + createServiceFactory({ service: coreServices.rootHttpRouter, deps: { config: coreServices.rootConfig, @@ -122,5 +123,10 @@ export const rootHttpRouterServiceFactory = createServiceFactory( return router; }, - }), + })(); + +/** @public */ +export const rootHttpRouterServiceFactory = Object.assign( + rootHttpRouterServiceFactoryWithOptions, + rootHttpRouterServiceFactoryWithOptions(), ); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts index c5c4c8708a..3e0782d4a3 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts @@ -347,6 +347,7 @@ describe('PluginTaskManagerImpl', () => { expect(parseDuration({ milliseconds: 5000 })).toEqual('PT5S'); expect(parseDuration(Duration.fromMillis(5000))).toEqual('PT5S'); expect(parseDuration({ cron: '1 * * * *' })).toEqual('1 * * * *'); + expect(parseDuration({ trigger: 'manual' })).toEqual('manual'); }); }); }); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts index 40aa9d521c..f8d06baf56 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts @@ -155,6 +155,9 @@ export function parseDuration( if (typeof frequency === 'object' && 'cron' in frequency) { return frequency.cron; } + if (typeof frequency === 'object' && 'trigger' in frequency) { + return frequency.trigger; + } const parsed = Duration.isDuration(frequency) ? frequency diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.test.ts index 1cafe00670..5db82f3ece 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.test.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.test.ts @@ -503,4 +503,32 @@ describe('TaskWorker', () => { await knex.destroy(); }, ); + + it.each(databases.eachSupportedId())( + 'next_run_start_at is not set for manually-triggered tasks, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn( + async () => new Promise(resolve => setTimeout(resolve, 50)), + ); + + const initialSettings: TaskSettingsV2 = { + version: 2, + cadence: 'manual', + timeoutAfterDuration: 'PT1M', + }; + + const worker = new TaskWorker('task99', fn, knex, logger); + await worker.persistTask(initialSettings); + await worker.tryClaimTask('ticket', initialSettings); + await worker.tryReleaseTask('ticket', initialSettings); + + const row = (await knex(DB_TASKS_TABLE))[0]; + expect(row.next_run_start_at).toBeNull(); + + await knex.destroy(); + }, + ); }); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.ts index a1c4ec44fd..c5570a8e30 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.ts @@ -53,8 +53,8 @@ export class TaskWorker { ); let workCheckFrequency = this.workCheckFrequency; - const isCron = !settings?.cadence.startsWith('P'); - if (!isCron) { + const isDuration = settings?.cadence.startsWith('P'); + if (isDuration) { const cadence = Duration.fromISO(settings.cadence); if (cadence < workCheckFrequency) { workCheckFrequency = cadence; @@ -175,7 +175,9 @@ export class TaskWorker { // read it back again. taskSettingsV2Schema.parse(settings); - const isCron = !settings?.cadence.startsWith('P'); + const isManual = settings?.cadence === 'manual'; + const isDuration = settings?.cadence.startsWith('P'); + const isCron = !isManual && !isDuration; let startAt: Knex.Raw | undefined; let nextStartAt: Knex.Raw | undefined; @@ -194,6 +196,9 @@ export class TaskWorker { nextStartAt = this.nextRunAtRaw(time); startAt ||= nextStartAt; + } else if (isManual) { + nextStartAt = this.knex.raw('null'); + startAt ||= nextStartAt; } else { startAt ||= this.knex.fn.now(); nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex); @@ -317,7 +322,9 @@ export class TaskWorker { ticket: string, settings: TaskSettingsV2, ): Promise { - const isCron = !settings?.cadence.startsWith('P'); + const isManual = settings?.cadence === 'manual'; + const isDuration = settings?.cadence.startsWith('P'); + const isCron = !isManual && !isDuration; let nextRun: Knex.Raw; if (isCron) { @@ -325,6 +332,8 @@ export class TaskWorker { this.logger.debug(`task: ${this.taskId} will next occur around ${time}`); nextRun = this.nextRunAtRaw(time); + } else if (isManual) { + nextRun = this.knex.raw('null'); } else { const dt = Duration.fromISO(settings.cadence).as('seconds'); this.logger.debug( diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts index 61e6c1d9a8..173c989543 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts @@ -40,6 +40,10 @@ function isValidCronFormat(c: string | undefined): boolean { } } +function isValidTrigger(t: string): boolean { + return t === 'manual'; +} + export const taskSettingsV1Schema = z.object({ version: z.literal(1), initialDelayDuration: z @@ -68,6 +72,11 @@ export const taskSettingsV2Schema = z.object({ cadence: z .string() .refine(isValidCronFormat, { message: 'Invalid cron' }) + .or( + z.string().refine(isValidTrigger, { + message: "Invalid trigger, expecting 'manual'", + }), + ) .or( z.string().refine(isValidOptionalDurationString, { message: 'Invalid duration, expecting ISO Period', diff --git a/packages/backend-defaults/src/entrypoints/urlReader/index.ts b/packages/backend-defaults/src/entrypoints/urlReader/index.ts index cf927ea031..05271966c9 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/index.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/index.ts @@ -15,4 +15,7 @@ */ export * from './lib'; -export { urlReaderServiceFactory } from './urlReaderServiceFactory'; +export { + urlReaderServiceFactory, + urlReaderFactoriesServiceRef, +} from './urlReaderServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts index 7f02f1468f..5a2655ad1c 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts @@ -213,6 +213,7 @@ export class AwsCodeCommitUrlReader implements UrlReaderService { ); const codeCommit = new CodeCommitClient({ + customUserAgent: 'backstage-aws-codecommit-url-reader', region: region, credentials: credentials, }); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts index 27f60f5b77..324538add4 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts @@ -222,6 +222,7 @@ export class AwsS3UrlReader implements UrlReaderService { ); const s3 = new S3Client({ + customUserAgent: 'backstage-aws-s3-url-reader', region: region, credentials: credentials, endpoint: integration.config.endpoint, diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts index ce2385507b..f53a7b6c11 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts @@ -26,7 +26,7 @@ import { import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -76,7 +76,7 @@ describe('AzureUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('read', () => { beforeEach(() => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts index dc182af619..f5caade3fa 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -56,7 +56,7 @@ describe('BitbucketCloudUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('readUrl', () => { it('should be able to readUrl via buffer without ETag', async () => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts index 2870138535..6af2858cde 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -51,7 +51,7 @@ const reader = new BitbucketServerUrlReader( describe('BitbucketServerUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('readTree', () => { const repoBuffer = fs.readFileSync( diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts index edd8d6d3fc..54880aaa75 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts @@ -22,7 +22,7 @@ import { import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -104,7 +104,7 @@ describe('BitbucketUrlReader', () => { ); const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('readUrl', () => { it('should be able to readUrl via buffer without ETag', async () => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts index 38936806c6..f84422c564 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts @@ -18,7 +18,7 @@ import { ConfigReader } from '@backstage/config'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -30,7 +30,7 @@ const fetchUrlReader = new FetchUrlReader(); describe('FetchUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts index 94627e074f..14ca4c018e 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts @@ -17,7 +17,7 @@ import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { NotModifiedError, NotFoundError } from '@backstage/errors'; @@ -92,7 +92,7 @@ const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { // eslint-disable-next-line jest/no-disabled-tests describe.skip('GerritUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { mockDir.clear(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts index 0b5983eefd..77c995c552 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts @@ -16,7 +16,7 @@ import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { GiteaIntegration, readGiteaConfig } from '@backstage/integration'; @@ -64,7 +64,7 @@ const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { describe('GiteaUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); afterAll(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts index f07ada0cc3..f1dd7c0dc6 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts @@ -22,7 +22,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -74,7 +74,7 @@ const gheProcessor = new GithubUrlReader( describe('GithubUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(mockDir.clear); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts index 46276fcdda..dd6a0970d2 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts @@ -18,7 +18,7 @@ import { ConfigReader } from '@backstage/config'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -72,7 +72,7 @@ describe('GitlabUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('read', () => { beforeEach(() => { 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/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts index f1efbca108..004e1931d0 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts @@ -16,7 +16,7 @@ import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { HarnessIntegration, readHarnessConfig } from '@backstage/integration'; @@ -120,7 +120,7 @@ const handlers = [ describe('HarnessUrlReader', () => { const worker = setupServer(...handlers); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeAll(() => worker.listen({ onUnhandledRequest: 'bypass' })); afterAll(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/urlReaderServiceFactory.ts b/packages/backend-defaults/src/entrypoints/urlReader/urlReaderServiceFactory.ts index 810882edf8..2639e99d83 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/urlReaderServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/urlReaderServiceFactory.ts @@ -14,12 +14,36 @@ * limitations under the License. */ +import { ReaderFactory } from './lib'; import { UrlReaders } from './lib/UrlReaders'; import { coreServices, createServiceFactory, + createServiceRef, } from '@backstage/backend-plugin-api'; +/** + * @public + * A non-singleton reference to URL Reader factory services. + * + * @example + * Creating a service factory implementation for a Custom URL Reader. + * ```ts + * createServiceFactory({ + * service: urlReaderFactoriesServiceRef, + * deps: {}, + * async factory() { + * return CustomUrlReader.factory; + * }, + * }); + * ``` + */ +export const urlReaderFactoriesServiceRef = createServiceRef({ + id: 'core.urlReader.factories', + scope: 'plugin', + multiton: true, +}); + /** * Reading content from external systems. * @@ -34,11 +58,13 @@ export const urlReaderServiceFactory = createServiceFactory({ deps: { config: coreServices.rootConfig, logger: coreServices.logger, + factories: urlReaderFactoriesServiceRef, }, - async factory({ config, logger }) { + async factory({ config, logger, factories }) { return UrlReaders.default({ config, logger, + factories, }); }, }); diff --git a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts index b63b24fb18..692d179ee2 100644 --- a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts +++ b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts @@ -17,7 +17,7 @@ import { BackstageUserPrincipal } from '@backstage/backend-plugin-api'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { JsonObject } from '@backstage/types'; import { SignJWT, base64url, importJWK } from 'jose'; @@ -28,7 +28,7 @@ import { DefaultUserInfoService } from './DefaultUserInfoService'; describe('DefaultUserInfoService', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); const mockPublicKey = { kty: 'EC', diff --git a/packages/backend-defaults/src/migrations.test.ts b/packages/backend-defaults/src/migrations.test.ts new file mode 100644 index 0000000000..579c32e626 --- /dev/null +++ b/packages/backend-defaults/src/migrations.test.ts @@ -0,0 +1,123 @@ +/* + * 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 { Knex } from 'knex'; +import { TestDatabases } from '@backstage/backend-test-utils'; +import fs from 'fs'; + +const migrationsDir = `${__dirname}/../migrations/scheduler`; +const migrationsFiles = fs.readdirSync(migrationsDir).sort(); + +async function migrateUpOnce(knex: Knex): Promise { + await knex.migrate.up({ directory: migrationsDir }); +} + +async function migrateDownOnce(knex: Knex): Promise { + await knex.migrate.down({ directory: migrationsDir }); +} + +async function migrateUntilBefore(knex: Knex, target: string): Promise { + const index = migrationsFiles.indexOf(target); + if (index === -1) { + throw new Error(`Migration ${target} not found`); + } + for (let i = 0; i < index; i++) { + await migrateUpOnce(knex); + } +} + +jest.setTimeout(60_000); + +describe('migrations', () => { + const databases = TestDatabases.create(); + + it.each(databases.eachSupportedId())( + '20210928160613_init.js, %p', + async databaseId => { + const knex = await databases.init(databaseId); + + await migrateUntilBefore(knex, '20210928160613_init.js'); + await migrateUpOnce(knex); + + await knex('backstage_backend_tasks__tasks').insert({ + id: 'test', + settings_json: '{}', + next_run_start_at: knex.fn.now(), + }); + + await expect(knex('backstage_backend_tasks__tasks')).resolves.toEqual([ + { + id: 'test', + settings_json: '{}', + next_run_start_at: expect.anything(), + current_run_ticket: null, + current_run_started_at: null, + current_run_expires_at: null, + }, + ]); + + await migrateDownOnce(knex); + + // This looks odd - you might expect a .toThrow at the end but that + // actually is flaky for some reason specifically on sqlite when + // performing multiple runs in sequence + await expect(knex('backstage_backend_tasks__tasks')).rejects.toEqual( + expect.anything(), + ); + + await knex.destroy(); + }, + ); + + it.each(databases.eachSupportedId())( + '20240712211735_nullable_next_run.js, %p', + async databaseId => { + const knex = await databases.init(databaseId); + + await migrateUntilBefore(knex, '20240712211735_nullable_next_run.js'); + await migrateUpOnce(knex); + + await knex('backstage_backend_tasks__tasks').insert({ + id: 'test', + settings_json: '{}', + next_run_start_at: knex.raw('null'), + }); + + await expect(knex('backstage_backend_tasks__tasks')).resolves.toEqual([ + { + id: 'test', + settings_json: '{}', + next_run_start_at: null, + current_run_ticket: null, + current_run_started_at: null, + current_run_expires_at: null, + }, + ]); + + await migrateDownOnce(knex); + + await expect( + knex('backstage_backend_tasks__tasks').insert({ + id: 'test', + settings_json: '{}', + next_run_start_at: knex.raw('null'), + }), + ).rejects.toEqual(expect.anything()); + + await knex.destroy(); + }, + ); +}); diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 02f47ef7b4..14111873a1 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,110 @@ # @backstage/backend-dynamic-feature-service +## 0.2.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-app-api@0.8.1-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-app-node@0.1.23-next.2 + - @backstage/plugin-events-backend@0.3.10-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/cli-node@0.2.7 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.2.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-app-api@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-app-node@0.1.23-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-backend@0.3.10-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.23-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## 0.2.15 + +### Patch Changes + +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/cli-node@0.2.7 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-node@0.1.22 + - @backstage/plugin-events-backend@0.3.9 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/config-loader@1.8.1 + - @backstage/plugin-search-common@1.2.13 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.15-next.1 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/api-report.md b/packages/backend-dynamic-feature-service/api-report.md index 20db7db71b..97dea60170 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,22 @@ export interface DynamicPluginsFactoryOptions { } // @public (undocumented) -export const dynamicPluginsFeatureDiscoveryServiceFactory: () => ServiceFactory< +export const dynamicPluginsFeatureDiscoveryServiceFactory: ServiceFactoryCompat< FeatureDiscoveryService, - 'root' + 'root', + 'singleton', + undefined >; // @public (undocumented) export const dynamicPluginsFrontendSchemas: BackendFeatureCompat; // @public (undocumented) -export const dynamicPluginsRootLoggerServiceFactory: () => ServiceFactory< +export const dynamicPluginsRootLoggerServiceFactory: ServiceFactoryCompat< RootLoggerService, - 'root' + 'root', + 'singleton', + undefined >; // @public (undocumented) @@ -142,19 +146,26 @@ export interface DynamicPluginsSchemasService { } // @public (undocumented) -export const dynamicPluginsSchemasServiceFactory: ( - options?: DynamicPluginsSchemasOptions | undefined, -) => ServiceFactory; +export const dynamicPluginsSchemasServiceFactory: ServiceFactoryCompat< + DynamicPluginsSchemasService, + 'root', + 'singleton', + DynamicPluginsSchemasOptions +>; // @public (undocumented) -export const dynamicPluginsServiceFactory: ( - options?: DynamicPluginsFactoryOptions | undefined, -) => ServiceFactory; +export const dynamicPluginsServiceFactory: ServiceFactoryCompat< + DynamicPluginProvider, + 'root', + 'singleton', + DynamicPluginsFactoryOptions +>; // @public (undocumented) export const dynamicPluginsServiceRef: ServiceRef< DynamicPluginProvider, - 'root' + 'root', + 'singleton' >; // @public (undocumented) diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 3e3e566879..d6ac21a3ae 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-dynamic-feature-service", "description": "Backstage dynamic feature service", - "version": "0.2.15-next.1", + "version": "0.2.16-next.2", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-legacy/CHANGELOG.md b/packages/backend-legacy/CHANGELOG.md index 35ed7a6c93..a601890055 100644 --- a/packages/backend-legacy/CHANGELOG.md +++ b/packages/backend-legacy/CHANGELOG.md @@ -1,5 +1,172 @@ # example-backend-legacy +## 0.2.101-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.23.1-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.2 + - @backstage/plugin-kubernetes-backend@0.18.4-next.2 + - @backstage/plugin-permission-backend@0.5.47-next.2 + - @backstage/plugin-devtools-backend@0.3.9-next.2 + - @backstage/plugin-techdocs-backend@1.10.10-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-signals-backend@0.1.9-next.2 + - @backstage/plugin-proxy-backend@0.5.4-next.2 + - @backstage/plugin-auth-backend@0.22.10-next.2 + - @backstage/plugin-app-backend@0.3.72-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-backend@1.5.15-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.2 + - @backstage/plugin-events-backend@0.3.10-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.2.101-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.10.10-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.1 + - @backstage/plugin-scaffolder-backend@1.23.1-next.1 + - @backstage/plugin-auth-backend@0.22.10-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.1 + - example-app@0.2.100-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-app-backend@0.3.72-next.1 + - @backstage/plugin-devtools-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.5.4-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-backend@0.18.4-next.1 + - @backstage/plugin-permission-backend@0.5.47-next.1 + - @backstage/plugin-search-backend@1.5.15-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.1 + - @backstage/plugin-events-backend@0.3.10-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.1 + - @backstage/plugin-signals-backend@0.1.9-next.1 + - @backstage/plugin-signals-node@0.1.9-next.1 + +## 0.2.101-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.0 + - example-app@0.2.100-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + +## 0.2.100 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.39 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-events-backend@0.3.9 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.3 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-pg@0.5.32 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/plugin-signals-node@0.1.8 + - example-app@0.2.99 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.2.100-next.2 ### Patch Changes diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index a537361746..a650924720 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-legacy", - "version": "0.2.100-next.2", + "version": "0.2.101-next.2", "backstage": { "role": "backend" }, diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 43a57f7d8c..682036d984 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/backend-openapi-utils +## 0.1.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/errors@1.2.4 + +## 0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/errors@1.2.4 + +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + +## 0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/errors@1.2.4 + ## 0.1.15-next.1 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index f35863c6e3..35db691c25 100644 --- a/packages/backend-openapi-utils/package.json +++ b/packages/backend-openapi-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-openapi-utils", "description": "OpenAPI typescript support.", - "version": "0.1.15-next.1", + "version": "0.1.16-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index cb341b218e..d404d05b33 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,222 @@ # @backstage/backend-plugin-api +## 0.8.0-next.2 + +### Minor Changes + +- 7c5f3b0: The `createServiceRef` function now accepts a new boolean `multiple` option. The `multiple` option defaults to `false` and when set to `true`, it enables that multiple implementation are installed for the created service ref. + + We're looking for ways to make it possible to augment services without the need to replace the entire service. + + Typical example of that being the ability to install support for additional targets for the `UrlReader` service without replacing the service itself. This achieves that by allowing us to define services that can have multiple simultaneous implementation, allowing the `UrlReader` implementation to depend on such a service to collect all possible implementation of support for external targets: + + ```diff + // @backstage/backend-defaults + + + export const urlReaderFactoriesServiceRef = createServiceRef({ + + id: 'core.urlReader.factories', + + scope: 'plugin', + + multiton: true, + + }); + + ... + + export const urlReaderServiceFactory = createServiceFactory({ + service: coreServices.urlReader, + deps: { + config: coreServices.rootConfig, + logger: coreServices.logger, + + factories: urlReaderFactoriesServiceRef, + }, + - async factory({ config, logger }) { + + async factory({ config, logger, factories }) { + return UrlReaders.default({ + config, + logger, + + factories, + }); + }, + }); + ``` + + With that, you can then add more custom `UrlReader` factories by installing more implementations of the `urlReaderFactoriesServiceRef` in your backend instance. Something like: + + ```ts + // packages/backend/index.ts + import { createServiceFactory } from '@backstage/backend-plugin-api'; + import { urlReaderFactoriesServiceRef } from '@backstage/backend-defaults'; + ... + + backend.add(createServiceFactory({ + service: urlReaderFactoriesServiceRef, + deps: {}, + async factory() { + return CustomUrlReader.factory; + }, + })); + + ... + + ``` + +### Patch Changes + +- 6061061: Added `createBackendFeatureLoader`, which can be used to create an installable backend feature that can in turn load in additional backend features in a dynamic way. +- ba9abf4: The `SchedulerService` now allows tasks with `frequency: { trigger: 'manual' }`. This means that the task will not be scheduled, but rather run only when manually triggered with `SchedulerService.triggerTask`. +- 8b13183: Added `createBackendFeatureLoader`, which can be used to programmatically select and install backend features. + + A feature loader can return an list of features to be installed, for example in the form on an `Array` or other for of iterable, which allows for the loader to be defined as a generator function. Both synchronous and asynchronous loaders are supported. + + Additionally, a loader can depend on services in its implementation, with the restriction that it can only depend on root-scoped services, and it may not override services that have already been instantiated. + + ```ts + const searchLoader = createBackendFeatureLoader({ + deps: { + config: coreServices.rootConfig, + }, + *loader({ config }) { + // Example of a custom config flag to enable search + if (config.getOptionalString('customFeatureToggle.search')) { + yield import('@backstage/plugin-search-backend/alpha'); + yield import('@backstage/plugin-search-backend-module-catalog/alpha'); + yield import('@backstage/plugin-search-backend-module-explore/alpha'); + yield import('@backstage/plugin-search-backend-module-techdocs/alpha'); + } + }, + }); + ``` + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.7.1-next.1 + +### Patch Changes + +- f011d1b: fix typo in `getPluginRequestToken` comments +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## 0.7.0 + +### Minor Changes + +- 36f91e8: **BREAKING**: The `PermissionsService` no longer supports passing the deprecated `token` option, and the request options are now required. + +### Patch Changes + +- 53ced70: Added a new Root Health Service which adds new endpoints for health checks. +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- 062c01c: Deprecated the ability to define options for service factories through `createServiceFactory`. In the future all service factories will return a plain `ServiceFactory` object, rather than allowing users to pass options to the factory. To allow for customization of a service implementation one can instead export one or a few building blocks that allows for simple re-implementation of the service instead. + + For example, instead of: + + ```ts + export const fooServiceFactory = createServiceFactory( + (options?: { bar: string }) => ({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }), + ); + ``` + + We instead encourage service implementations to provide an easy to use API for re-implementing the service for advanced use-cases: + + ```ts + /** @public */ + export class DefaultFooService implements FooService { + static create(options: { bar: string; logger: LoggerService }) { + return new DefaultFooService(options.logger, options.bar ?? 'default'); + } + + private constructor( + private readonly logger: string, + private readonly bar: string, + ) {} + + // The rest of the implementation + } + ``` + + A user that wishes to customize the service can then easily do so by defining their own factory: + + ```ts + export const customFooServiceFactory = createServiceFactory({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return DefaultFooService.create({ logger, bar: 'baz' }); + }, + }); + ``` + + This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead. + + In cases where the old options patterns significantly improves the usability of the service factory, the old pattern can still be implemented like this: + + ```ts + const fooServiceFactoryWithOptions = (options?: { bar: string }) => + createServiceFactory({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }); + + export const fooServiceFactory = Object.assign( + fooServiceFactoryWithOptions, + fooServiceFactoryWithOptions(), + ); + ``` + + This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection. + + A separate benefit of this change is that it simplifies the TypeScript types in a way that allows TypeScript to provide a much better error message when a service factory doesn't properly implement the service interface. + +- fe47a3e: All service config types were renamed to option types in order to standardize frontend and backend `create*` function signatures: + + - The `ServiceRefConfig` type was renamed to`ServiceRefOptions`; + - The `RootServiceFactoryConfig` type was renamed to `RootServiceFactoryOptions`; + - The `PluginServiceFactoryConfig` type was renamed to `PluginServiceFactoryOptions` + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.6.22-next.1 ### Patch Changes diff --git a/packages/backend-plugin-api/api-report-alpha.md b/packages/backend-plugin-api/api-report-alpha.md index 81b378a671..0f4348336a 100644 --- a/packages/backend-plugin-api/api-report-alpha.md +++ b/packages/backend-plugin-api/api-report-alpha.md @@ -17,7 +17,8 @@ export interface FeatureDiscoveryService { // @alpha export const featureDiscoveryServiceRef: ServiceRef< FeatureDiscoveryService, - 'root' + 'root', + 'singleton' >; // (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 7b1e6ef2d3..e5189dce4d 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -9,6 +9,7 @@ import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common' import { AuthorizePermissionResponse } from '@backstage/plugin-permission-common'; import { Config } from '@backstage/config'; import { Duration } from 'luxon'; +import { EvaluatorRequestOptions } from '@backstage/plugin-permission-common'; import { Handler } from 'express'; import { HumanDuration } from '@backstage/types'; import { IdentityApi } from '@backstage/plugin-auth-node'; @@ -188,28 +189,73 @@ export type CacheServiceSetOptions = { // @public export namespace coreServices { - const auth: ServiceRef; - const userInfo: ServiceRef; - const cache: ServiceRef; - const rootConfig: ServiceRef; - const database: ServiceRef; - const discovery: ServiceRef; - const rootHealth: ServiceRef; - const httpAuth: ServiceRef; - const httpRouter: ServiceRef; - const lifecycle: ServiceRef; - const logger: ServiceRef; - const permissions: ServiceRef; - const pluginMetadata: ServiceRef; - const rootHttpRouter: ServiceRef; - const rootLifecycle: ServiceRef; - const rootLogger: ServiceRef; - const scheduler: ServiceRef; + const auth: ServiceRef; + const userInfo: ServiceRef; + const cache: ServiceRef; + const rootConfig: ServiceRef; + const database: ServiceRef; + const discovery: ServiceRef; + const rootHealth: ServiceRef; + const httpAuth: ServiceRef; + const httpRouter: ServiceRef; + const lifecycle: ServiceRef; + const logger: ServiceRef; + const permissions: ServiceRef; + const pluginMetadata: ServiceRef< + PluginMetadataService, + 'plugin', + 'singleton' + >; + const rootHttpRouter: ServiceRef; + const rootLifecycle: ServiceRef; + const rootLogger: ServiceRef; + const scheduler: ServiceRef; const // @deprecated - tokenManager: ServiceRef; - const urlReader: ServiceRef; + tokenManager: ServiceRef; + const urlReader: ServiceRef; const // @deprecated - identity: ServiceRef; + identity: ServiceRef; +} + +// @public +export function createBackendFeatureLoader< + TDeps extends { + [name in string]: unknown; + }, +>(options: CreateBackendFeatureLoaderOptions): BackendFeature; + +// @public +export interface CreateBackendFeatureLoaderOptions< + TDeps extends { + [name in string]: unknown; + }, +> { + // (undocumented) + deps?: { + [name in keyof TDeps]: ServiceRef; + }; + // (undocumented) + loader(deps: TDeps): + | Iterable< + | BackendFeature + | Promise<{ + default: BackendFeature; + }> + > + | Promise< + Iterable< + | BackendFeature + | Promise<{ + default: BackendFeature; + }> + > + > + | AsyncIterable< + | BackendFeature + | { + default: BackendFeature; + } + >; } // @public @@ -250,18 +296,20 @@ export interface CreateExtensionPointOptions { // @public export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef; }, TOpts extends object | undefined = undefined, >( - options: RootServiceFactoryOptions, -): () => ServiceFactory; + options: RootServiceFactoryOptions, +): ServiceFactoryCompat; -// @public +// @public @deprecated export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef; @@ -270,12 +318,13 @@ export function createServiceFactory< >( options: ( options?: TOpts, - ) => RootServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; + ) => RootServiceFactoryOptions, +): ServiceFactoryCompat; // @public export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef; @@ -283,12 +332,19 @@ export function createServiceFactory< TContext = undefined, TOpts extends object | undefined = undefined, >( - options: PluginServiceFactoryOptions, -): () => ServiceFactory; + options: PluginServiceFactoryOptions< + TService, + TInstances, + TContext, + TImpl, + TDeps + >, +): ServiceFactoryCompat; -// @public +// @public @deprecated export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef; @@ -298,18 +354,34 @@ export function createServiceFactory< >( options: ( options?: TOpts, - ) => PluginServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; + ) => PluginServiceFactoryOptions< + TService, + TInstances, + TContext, + TImpl, + TDeps + >, +): ServiceFactoryCompat; // @public export function createServiceRef( - options: ServiceRefOptions, -): ServiceRef; + options: ServiceRefOptions, +): ServiceRef; // @public export function createServiceRef( - options: ServiceRefOptions, -): ServiceRef; + options: ServiceRefOptions, +): ServiceRef; + +// @public +export function createServiceRef( + options: ServiceRefOptions, +): ServiceRef; + +// @public +export function createServiceRef( + options: ServiceRefOptions, +): ServiceRef; // @public export interface DatabaseService { @@ -423,22 +495,20 @@ export interface LoggerService { export interface PermissionsService extends PermissionEvaluator { authorize( requests: AuthorizePermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; authorizeConditional( requests: QueryPermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; } // @public -export type PermissionsServiceRequestOptions = - | { - token?: string; - } - | { - credentials: BackstageCredentials; - }; +export interface PermissionsServiceRequestOptions + extends EvaluatorRequestOptions { + // (undocumented) + credentials: BackstageCredentials; +} // @public export interface PluginMetadataService { @@ -448,16 +518,18 @@ export interface PluginMetadataService { // @public @deprecated (undocumented) export type PluginServiceFactoryConfig< TService, + TInstances extends 'singleton' | 'multiton', TContext, TImpl extends TService, TDeps extends { [name in string]: ServiceRef; }, -> = PluginServiceFactoryOptions; +> = PluginServiceFactoryOptions; // @public (undocumented) export interface PluginServiceFactoryOptions< TService, + TInstances extends 'singleton' | 'multiton', TContext, TImpl extends TService, TDeps extends { @@ -477,7 +549,7 @@ export interface PluginServiceFactoryOptions< ): TImpl | Promise; initialization?: 'always' | 'lazy'; // (undocumented) - service: ServiceRef; + service: ServiceRef; } // @public @@ -539,15 +611,17 @@ export interface RootLoggerService extends LoggerService {} // @public @deprecated (undocumented) export type RootServiceFactoryConfig< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef; }, -> = RootServiceFactoryOptions; +> = RootServiceFactoryOptions; // @public (undocumented) export interface RootServiceFactoryOptions< - TService, + TService, // TODO(Rugvip): Can we forward the entire service ref type here instead of forwarding each type arg once the callback form is gone? + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef; @@ -559,7 +633,7 @@ export interface RootServiceFactoryOptions< factory(deps: ServiceRefsToInstances): TImpl | Promise; initialization?: 'always' | 'lazy'; // (undocumented) - service: ServiceRef; + service: ServiceRef; } // @public @@ -608,7 +682,10 @@ export interface SchedulerServiceTaskScheduleDefinition { cron: string; } | Duration - | HumanDuration; + | HumanDuration + | { + trigger: 'manual'; + }; initialDelay?: Duration | HumanDuration; scope?: 'global' | 'local'; timeout: Duration | HumanDuration; @@ -621,7 +698,14 @@ export interface SchedulerServiceTaskScheduleDefinitionConfig { cron: string; } | string - | HumanDuration; + | HumanDuration + /** + * This task will only run when manually triggered with the `triggerTask` method; no automatic + * scheduling. This is useful for locking of global tasks that should not be run concurrently. + */ + | { + trigger: 'manual'; + }; initialDelay?: string | HumanDuration; scope?: 'global' | 'local'; timeout: string | HumanDuration; @@ -640,21 +724,37 @@ export type SearchResponseFile = UrlReaderServiceSearchResponseFile; export interface ServiceFactory< TService = unknown, TScope extends 'plugin' | 'root' = 'plugin' | 'root', + TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton', > extends BackendFeature { // (undocumented) - service: ServiceRef; + service: ServiceRef; } -// @public +// @public @deprecated (undocumented) +export interface ServiceFactoryCompat< + TService = unknown, + TScope extends 'plugin' | 'root' = 'plugin' | 'root', + TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton', + TOpts extends object | undefined = undefined, +> extends ServiceFactory { + // @deprecated (undocumented) + ( + ...options: undefined extends TOpts ? [] : [options?: TOpts] + ): ServiceFactory; +} + +// @public @deprecated export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory); // @public export type ServiceRef< TService, TScope extends 'root' | 'plugin' = 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton', > = { id: string; scope: TScope; + multiton?: TInstances extends 'multiton' ? true : false; T: TService; $$type: '@backstage/ServiceRef'; }; @@ -663,17 +763,28 @@ export type ServiceRef< export type ServiceRefConfig< TService, TScope extends 'root' | 'plugin', -> = ServiceRefOptions; + TInstances extends 'singleton' | 'multiton', +> = ServiceRefOptions; // @public (undocumented) -export interface ServiceRefOptions { +export interface ServiceRefOptions< + TService, + TScope extends 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton', +> { // (undocumented) - defaultFactory?: ( + defaultFactory?( service: ServiceRef, - ) => Promise; + ): Promise; + // @deprecated (undocumented) + defaultFactory?( + service: ServiceRef, + ): Promise<() => ServiceFactory>; // (undocumented) id: string; // (undocumented) + multiton?: TInstances extends 'multiton' ? true : false; + // (undocumented) scope?: TScope; } diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 631141a57f..61f8b9353d 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-plugin-api", - "version": "0.6.22-next.1", + "version": "0.8.0-next.2", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" diff --git a/packages/backend-plugin-api/src/deprecated.ts b/packages/backend-plugin-api/src/deprecated.ts index 17ccccf320..0d02f9ed7e 100644 --- a/packages/backend-plugin-api/src/deprecated.ts +++ b/packages/backend-plugin-api/src/deprecated.ts @@ -28,7 +28,8 @@ import { export type ServiceRefConfig< TService, TScope extends 'root' | 'plugin', -> = ServiceRefOptions; + TInstances extends 'singleton' | 'multiton', +> = ServiceRefOptions; /** * @public @@ -36,9 +37,10 @@ export type ServiceRefConfig< */ export type RootServiceFactoryConfig< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, -> = RootServiceFactoryOptions; +> = RootServiceFactoryOptions; /** * @public @@ -46,7 +48,8 @@ export type RootServiceFactoryConfig< */ export type PluginServiceFactoryConfig< TService, + TInstances extends 'singleton' | 'multiton', TContext, TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, -> = PluginServiceFactoryOptions; +> = PluginServiceFactoryOptions; diff --git a/packages/backend-plugin-api/src/services/definitions/AuthService.ts b/packages/backend-plugin-api/src/services/definitions/AuthService.ts index dce5e9be3b..1e0cf6e56b 100644 --- a/packages/backend-plugin-api/src/services/definitions/AuthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/AuthService.ts @@ -208,7 +208,7 @@ export interface AuthService { * * @remarks * - * This method should be called before each request. Do not cold on to the + * This method should be called before each request. Do not hold on to the * issued token and reuse it for future calls. */ getPluginRequestToken(options: { diff --git a/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts b/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts index c5046a988b..a25081d17a 100644 --- a/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts +++ b/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts @@ -17,6 +17,7 @@ import { AuthorizePermissionRequest, AuthorizePermissionResponse, + EvaluatorRequestOptions, PermissionEvaluator, QueryPermissionRequest, QueryPermissionResponse, @@ -24,18 +25,14 @@ import { import { BackstageCredentials } from './AuthService'; /** - * Options for {@link @backstage/plugin-permission-common#PermissionEvaluator} requests. + * Options for {@link PermissionsService} requests. * * @public */ -export type PermissionsServiceRequestOptions = - | { - /** @deprecated use the `credentials` option instead. */ - token?: string; - } - | { - credentials: BackstageCredentials; - }; +export interface PermissionsServiceRequestOptions + extends EvaluatorRequestOptions { + credentials: BackstageCredentials; +} /** * Permission system integration for authorization of user/service actions. @@ -59,7 +56,7 @@ export interface PermissionsService extends PermissionEvaluator { */ authorize( requests: AuthorizePermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; /** @@ -79,6 +76,6 @@ export interface PermissionsService extends PermissionEvaluator { */ authorizeConditional( requests: QueryPermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; } diff --git a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts index a7ec79a336..a8b84b9084 100644 --- a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts +++ b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts @@ -96,7 +96,8 @@ export interface SchedulerServiceTaskScheduleDefinition { cron: string; } | Duration - | HumanDuration; + | HumanDuration + | { trigger: 'manual' }; /** * The maximum amount of time that a single task invocation can take, before @@ -193,7 +194,12 @@ export interface SchedulerServiceTaskScheduleDefinitionConfig { cron: string; } | string - | HumanDuration; + | HumanDuration + /** + * This task will only run when manually triggered with the `triggerTask` method; no automatic + * scheduling. This is useful for locking of global tasks that should not be run concurrently. + */ + | { trigger: 'manual' }; /** * The maximum amount of time that a single task invocation can take, before @@ -361,14 +367,20 @@ function readDuration(config: Config, key: string): HumanDuration { return readDurationFromConfig(config, { key }); } -function readCronOrDuration( +function readFrequency( config: Config, key: string, -): { cron: string } | HumanDuration { +): { cron: string } | HumanDuration | { trigger: 'manual' } { const value = config.get(key); if (typeof value === 'object' && (value as { cron?: string }).cron) { return value as { cron: string }; } + if ( + typeof value === 'object' && + (value as { trigger?: string }).trigger === 'manual' + ) { + return { trigger: 'manual' }; + } return readDuration(config, key); } @@ -383,7 +395,7 @@ function readCronOrDuration( export function readSchedulerServiceTaskScheduleDefinitionFromConfig( config: Config, ): SchedulerServiceTaskScheduleDefinition { - const frequency = readCronOrDuration(config, 'frequency'); + const frequency = readFrequency(config, 'frequency'); const timeout = readDuration(config, 'timeout'); const initialDelay = config.has('initialDelay') 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.test.ts b/packages/backend-plugin-api/src/services/system/types.test.ts index adf097761b..52322f998b 100644 --- a/packages/backend-plugin-api/src/services/system/types.test.ts +++ b/packages/backend-plugin-api/src/services/system/types.test.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { createServiceFactory, createServiceRef } from './types'; +import { + InternalServiceFactory, + createServiceFactory, + createServiceRef, +} from './types'; const ref = createServiceRef({ id: 'x' }); const rootDep = createServiceRef({ id: 'y', scope: 'root' }); @@ -36,6 +40,10 @@ describe('createServiceFactory', () => { }, }); expect(metaFactory).toEqual(expect.any(Function)); + expect(metaFactory().$$type).toBe('@backstage/BackendFeature'); + expect((metaFactory() as InternalServiceFactory).featureType).toBe( + 'service', + ); expect(metaFactory().service).toBe(ref); // @ts-expect-error @@ -324,6 +332,24 @@ describe('createServiceFactory', () => { metaFactory(); }); + it('should support old service refs without a multiton field', () => { + const oldPluginDep = pluginDep as Omit; // Old refs don't have a multiton field + const metaFactory = createServiceFactory({ + service: ref, + deps: { + plugin: oldPluginDep, + }, + async factory({ plugin }) { + const plugin1: boolean = plugin; + // @ts-expect-error + const plugin2: number = plugin; + unused(plugin1, plugin2); + return 'x'; + }, + }); + expect(metaFactory).toEqual(expect.any(Function)); + }); + it('should only allow objects as options', () => { // @ts-expect-error const metaFactory = createServiceFactory((_opts: string) => ({ diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 2d6951ffea..5bca592768 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -24,6 +24,7 @@ import { BackendFeature } from '../../types'; export type ServiceRef< TService, TScope extends 'root' | 'plugin' = 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton', > = { id: string; @@ -38,6 +39,8 @@ export type ServiceRef< */ scope: TScope; + multiton?: TInstances extends 'multiton' ? true : false; + /** * Utility for getting the type of the service, using `typeof serviceRef.T`. * Attempting to actually read this value will result in an exception. @@ -51,16 +54,37 @@ export type ServiceRef< export interface ServiceFactory< TService = unknown, TScope extends 'plugin' | 'root' = 'plugin' | 'root', + TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton', > extends BackendFeature { - service: ServiceRef; + 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', + TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton', + TOpts extends object | undefined = undefined, +> extends ServiceFactory { + /** + * @deprecated Callable service factories will be removed in a future release, please re-implement the service factory using the available APIs instead. If no options are being passed, you can simply remove the trailing `()`. + */ + ( + ...options: undefined extends TOpts ? [] : [options?: TOpts] + ): ServiceFactory; } /** @internal */ export interface InternalServiceFactory< TService = unknown, TScope extends 'plugin' | 'root' = 'plugin' | 'root', -> extends ServiceFactory { + TInstances extends 'singleton' | 'multiton' = 'singleton' | 'multiton', +> extends ServiceFactory { version: 'v1'; + featureType: 'service'; initialization?: 'always' | 'lazy'; deps: { [key in string]: ServiceRef }; createRootContext?(deps: { [key in string]: unknown }): Promise; @@ -73,17 +97,29 @@ 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); /** @public */ -export interface ServiceRefOptions { +export interface ServiceRefOptions< + TService, + TScope extends 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton', +> { id: string; scope?: TScope; - defaultFactory?: ( + multiton?: TInstances extends 'multiton' ? true : false; + 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>; } /** @@ -92,8 +128,8 @@ export interface ServiceRefOptions { * @public */ export function createServiceRef( - options: ServiceRefOptions, -): ServiceRef; + options: ServiceRefOptions, +): ServiceRef; /** * Creates a new service definition. This overload is used to create root scoped services. @@ -101,16 +137,37 @@ export function createServiceRef( * @public */ export function createServiceRef( - options: ServiceRefOptions, -): ServiceRef; + options: ServiceRefOptions, +): ServiceRef; +/** + * Creates a new service definition. This overload is used to create plugin scoped services. + * + * @public + */ export function createServiceRef( - options: ServiceRefOptions, -): ServiceRef { - const { id, scope = 'plugin', defaultFactory } = options; + options: ServiceRefOptions, +): ServiceRef; + +/** + * Creates a new service definition. This overload is used to create root scoped services. + * + * @public + */ +export function createServiceRef( + options: ServiceRefOptions, +): ServiceRef; +export function createServiceRef< + TService, + TInstances extends 'singleton' | 'multiton', +>( + options: ServiceRefOptions, +): ServiceRef { + const { id, scope = 'plugin', multiton = false, defaultFactory } = options; return { id, scope, + multiton, get T(): TService { throw new Error(`tried to read ServiceRef.T of ${this}`); }, @@ -119,7 +176,7 @@ export function createServiceRef( }, $$type: '@backstage/ServiceRef', __defaultFactory: defaultFactory, - } as ServiceRef & { + } as ServiceRef & { __defaultFactory?: ( service: ServiceRef, ) => Promise | (() => ServiceFactory)>; @@ -131,12 +188,17 @@ type ServiceRefsToInstances< T extends { [key in string]: ServiceRef }, TScope extends 'root' | 'plugin' = 'root' | 'plugin', > = { - [key in keyof T as T[key]['scope'] extends TScope ? key : never]: T[key]['T']; + [key in keyof T as T[key]['scope'] extends TScope + ? key + : never]: T[key]['multiton'] extends true | undefined + ? Array + : T[key]['T']; }; /** @public */ export interface RootServiceFactoryOptions< - TService, + TService, // TODO(Rugvip): Can we forward the entire service ref type here instead of forwarding each type arg once the callback form is gone? + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, > { @@ -151,7 +213,7 @@ export interface RootServiceFactoryOptions< * Service factories for root scoped services use `always` as the default, while plugin scoped services use `lazy`. */ initialization?: 'always' | 'lazy'; - service: ServiceRef; + service: ServiceRef; deps: TDeps; factory(deps: ServiceRefsToInstances): TImpl | Promise; } @@ -159,6 +221,7 @@ export interface RootServiceFactoryOptions< /** @public */ export interface PluginServiceFactoryOptions< TService, + TInstances extends 'singleton' | 'multiton', TContext, TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, @@ -174,7 +237,7 @@ export interface PluginServiceFactoryOptions< * Service factories for root scoped services use `always` as the default, while plugin scoped services use `lazy`. */ initialization?: 'always' | 'lazy'; - service: ServiceRef; + service: ServiceRef; deps: TDeps; createRootContext?( deps: ServiceRefsToInstances, @@ -193,28 +256,34 @@ export interface PluginServiceFactoryOptions< */ export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, TOpts extends object | undefined = undefined, >( - options: RootServiceFactoryOptions, -): () => ServiceFactory; + options: RootServiceFactoryOptions, +): 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. */ export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, TOpts extends object | undefined = undefined, >( options: ( options?: TOpts, - ) => RootServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; + ) => RootServiceFactoryOptions, +): ServiceFactoryCompat; /** * Creates a plugin scoped service factory without options. * @@ -223,21 +292,33 @@ export function createServiceFactory< */ export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, TContext = undefined, TOpts extends object | undefined = undefined, >( - options: PluginServiceFactoryOptions, -): () => ServiceFactory; + options: PluginServiceFactoryOptions< + TService, + TInstances, + TContext, + TImpl, + TDeps + >, +): 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. */ export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, TContext = undefined, @@ -245,44 +326,78 @@ export function createServiceFactory< >( options: ( options?: TOpts, - ) => PluginServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; + ) => PluginServiceFactoryOptions< + TService, + TInstances, + TContext, + TImpl, + TDeps + >, +): ServiceFactoryCompat; export function createServiceFactory< TService, + TInstances extends 'singleton' | 'multiton', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, TContext, TOpts extends object | undefined = undefined, >( options: - | RootServiceFactoryOptions - | PluginServiceFactoryOptions - | ((options: TOpts) => RootServiceFactoryOptions) + | RootServiceFactoryOptions + | PluginServiceFactoryOptions | (( options: TOpts, - ) => PluginServiceFactoryOptions) - | (() => RootServiceFactoryOptions) - | (() => PluginServiceFactoryOptions), -): (options: TOpts) => ServiceFactory { + ) => RootServiceFactoryOptions) + | (( + options: TOpts, + ) => PluginServiceFactoryOptions< + TService, + TInstances, + TContext, + TImpl, + TDeps + >) + | (() => RootServiceFactoryOptions) + | (() => PluginServiceFactoryOptions< + TService, + TInstances, + TContext, + TImpl, + TDeps + >), +): ServiceFactoryCompat< + TService, + 'root' | 'plugin', + 'singleton' | 'multiton', + TOpts +> { 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; + const c = anyConf as RootServiceFactoryOptions< + TService, + TInstances, + TImpl, + TDeps + >; return { $$type: '@backstage/BackendFeature', version: 'v1', + featureType: 'service', service: c.service, initialization: c.initialization, deps: c.deps, - factory: async (deps: TDeps) => c.factory(deps), + factory: async (deps: ServiceRefsToInstances) => + c.factory(deps), }; } const c = anyConf as PluginServiceFactoryOptions< TService, + TInstances, TContext, TImpl, TDeps @@ -290,20 +405,26 @@ export function createServiceFactory< return { $$type: '@backstage/BackendFeature', version: 'v1', + featureType: 'service', service: c.service, initialization: c.initialization, ...('createRootContext' in c ? { - createRootContext: async (deps: TDeps) => - c?.createRootContext?.(deps), + createRootContext: async ( + deps: ServiceRefsToInstances, + ) => c?.createRootContext?.(deps), } : {}), deps: c.deps, - factory: async (deps: TDeps, ctx: TContext) => c.factory(deps, ctx), + factory: async (deps: ServiceRefsToInstances, ctx: TContext) => + c.factory(deps, ctx), }; }; - 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-plugin-api/src/wiring/createBackendFeatureLoader.test.ts b/packages/backend-plugin-api/src/wiring/createBackendFeatureLoader.test.ts new file mode 100644 index 0000000000..37fc079551 --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createBackendFeatureLoader.test.ts @@ -0,0 +1,195 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { coreServices, createServiceFactory } from '../services'; +import { InternalServiceFactory } from '../services/system/types'; +import { BackendFeature } from '../types'; +import { createBackendFeatureLoader } from './createBackendFeatureLoader'; +import { createBackendPlugin } from './createBackendPlugin'; +import { InternalBackendFeatureLoader } from './types'; + +describe('createBackendFeatureLoader', () => { + it('should create an empty feature loader', () => { + const result = createBackendFeatureLoader({ + deps: {}, + loader: () => [], + }) as InternalBackendFeatureLoader; + + expect(result.$$type).toEqual('@backstage/BackendFeature'); + expect(result.version).toEqual('v1'); + expect(result.featureType).toEqual('loader'); + expect(result.deps).toEqual({}); + expect(result.loader).toEqual(expect.any(Function)); + expect(result.description).toMatch(/^created at '.*'$/); + }); + + it('should create a feature loader that loads a few features', async () => { + const result = createBackendFeatureLoader({ + deps: { + config: coreServices.rootConfig, + }, + loader({ config: _unused }) { + return [ + createBackendPlugin({ + pluginId: 'x', + register() {}, + })(), + createServiceFactory({ + service: coreServices.pluginMetadata, + deps: {}, + factory: () => ({ getId: () => 'fake-id' }), + })(), + // Dynamic import format + Promise.resolve({ + default: createBackendPlugin({ + pluginId: 'y', + register() {}, + })(), + }), + ]; + }, + }) as InternalBackendFeatureLoader; + + expect(result.$$type).toEqual('@backstage/BackendFeature'); + expect(result.version).toEqual('v1'); + expect(result.featureType).toEqual('loader'); + + const results = await result.loader({ config: {} }); + expect(results.length).toBe(3); + const [pluginX, serviceFactory, pluginY] = results; + expect(pluginX.$$type).toBe('@backstage/BackendFeature'); + expect(serviceFactory.$$type).toBe('@backstage/BackendFeature'); + expect(pluginY.$$type).toBe('@backstage/BackendFeature'); + expect((serviceFactory as InternalServiceFactory).service.id).toBe( + coreServices.pluginMetadata.id, + ); + }); + + it('should support multiple output formats', async () => { + const feature = createBackendPlugin({ pluginId: 'x', register() {} })(); + const dynamicFeature = Promise.resolve({ default: feature }); + + async function extractResult(f: BackendFeature) { + const internal = f as InternalBackendFeatureLoader; + return internal.loader({}); + } + + await expect( + extractResult( + createBackendFeatureLoader({ + loader() { + return [feature]; + }, + }), + ), + ).resolves.toEqual([feature]); + + await expect( + extractResult( + createBackendFeatureLoader({ + async loader() { + return [feature]; + }, + }), + ), + ).resolves.toEqual([feature]); + + await expect( + extractResult( + createBackendFeatureLoader({ + *loader() { + yield feature; + }, + }), + ), + ).resolves.toEqual([feature]); + + await expect( + extractResult( + createBackendFeatureLoader({ + async *loader() { + yield feature; + }, + }), + ), + ).resolves.toEqual([feature]); + + await expect( + extractResult( + createBackendFeatureLoader({ + loader() { + return [dynamicFeature]; + }, + }), + ), + ).resolves.toEqual([feature]); + + await expect( + extractResult( + createBackendFeatureLoader({ + async loader() { + return [dynamicFeature]; + }, + }), + ), + ).resolves.toEqual([feature]); + + await expect( + extractResult( + createBackendFeatureLoader({ + *loader() { + yield dynamicFeature; + }, + }), + ), + ).resolves.toEqual([feature]); + + await expect( + extractResult( + createBackendFeatureLoader({ + async *loader() { + yield dynamicFeature; + }, + }), + ), + ).resolves.toEqual([feature]); + }); + + it('should only allow dependencies on root scoped services', () => { + createBackendFeatureLoader({ + deps: { + rootLogger: coreServices.rootLogger, + }, + loader: () => [], + }); + createBackendFeatureLoader({ + deps: { + // @ts-expect-error + logger: coreServices.logger, + }, + loader: () => [], + }); + createBackendFeatureLoader({ + deps: { + rootLogger: coreServices.rootLogger, + // @ts-expect-error + logger: coreServices.logger, + }, + loader: () => [], + }); + expect('test').toBe('test'); + }); +}); diff --git a/packages/backend-plugin-api/src/wiring/createBackendFeatureLoader.ts b/packages/backend-plugin-api/src/wiring/createBackendFeatureLoader.ts new file mode 100644 index 0000000000..cfa3e96c65 --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createBackendFeatureLoader.ts @@ -0,0 +1,68 @@ +/* + * 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 } from '../services'; +import { BackendFeature } from '../types'; +import { describeParentCallSite } from './describeParentCallSite'; +import { InternalBackendFeatureLoader } from './types'; + +/** + * @public + * Options for creating a new backend feature loader. + */ +export interface CreateBackendFeatureLoaderOptions< + TDeps extends { [name in string]: unknown }, +> { + deps?: { + [name in keyof TDeps]: ServiceRef; + }; + loader( + deps: TDeps, + ): + | Iterable> + | Promise>> + | AsyncIterable; +} + +/** + * @public + * Creates a new backend feature loader. + */ +export function createBackendFeatureLoader< + TDeps extends { [name in string]: unknown }, +>(options: CreateBackendFeatureLoaderOptions): BackendFeature { + return { + $$type: '@backstage/BackendFeature', + version: 'v1', + featureType: 'loader', + description: `created at '${describeParentCallSite()}'`, + deps: options.deps, + async loader(deps: TDeps) { + const it = await options.loader(deps); + const result = new Array(); + for await (const item of it) { + if ('$$type' in item && item.$$type === '@backstage/BackendFeature') { + result.push(item); + } else if ('default' in item) { + result.push(item.default); + } else { + throw new Error(`Invalid item "${item}"`); + } + } + return result; + }, + } as InternalBackendFeatureLoader; +} diff --git a/packages/backend-plugin-api/src/wiring/createBackendModule.test.ts b/packages/backend-plugin-api/src/wiring/createBackendModule.test.ts new file mode 100644 index 0000000000..e3c9f9007a --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createBackendModule.test.ts @@ -0,0 +1,57 @@ +/* + * 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 { createBackendModule } from './createBackendModule'; +import { InternalBackendRegistrations } from './types'; + +describe('createBackendModule', () => { + it('should create a BackendModule', () => { + const result = createBackendModule({ + pluginId: 'x', + moduleId: 'y', + register(r) { + r.registerInit({ deps: {}, async init() {} }); + }, + }); + + // legacy form + const legacy = result() as unknown as InternalBackendRegistrations; + expect(legacy.$$type).toEqual('@backstage/BackendFeature'); + expect(legacy.version).toEqual('v1'); + expect(legacy.getRegistrations).toEqual(expect.any(Function)); + + // new form + const module = result as unknown as InternalBackendRegistrations; + expect(module.$$type).toEqual('@backstage/BackendFeature'); + expect(module.version).toEqual('v1'); + expect(module.getRegistrations).toEqual(expect.any(Function)); + expect(module.getRegistrations()).toEqual([ + { + type: 'module', + pluginId: 'x', + moduleId: 'y', + extensionPoints: [], + init: { + deps: expect.any(Object), + func: expect.any(Function), + }, + }, + ]); + + // @ts-expect-error + expect(module({ a: 'a' })).toBeDefined(); + }); +}); diff --git a/packages/backend-plugin-api/src/wiring/createBackendModule.ts b/packages/backend-plugin-api/src/wiring/createBackendModule.ts new file mode 100644 index 0000000000..56f041606e --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createBackendModule.ts @@ -0,0 +1,107 @@ +/* + * 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 { BackendFeatureCompat } from '../types'; +import { + BackendModuleRegistrationPoints, + InternalBackendModuleRegistration, + InternalBackendPluginRegistration, +} from './types'; + +/** + * The configuration options passed to {@link createBackendModule}. + * + * @public + * @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules} + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ +export interface CreateBackendModuleOptions { + /** + * Should exactly match the `id` of the plugin that the module extends. + * + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ + pluginId: string; + + /** + * The ID of this module, used to identify the module and ensure that it is not installed twice. + */ + moduleId: string; + register(reg: BackendModuleRegistrationPoints): void; +} + +/** + * Creates a new backend module for a given plugin. + * + * @public + * @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules} + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ +export function createBackendModule( + options: CreateBackendModuleOptions, +): BackendFeatureCompat { + function getRegistrations() { + const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] = + []; + let init: InternalBackendModuleRegistration['init'] | undefined = undefined; + + options.register({ + registerExtensionPoint(ext, impl) { + if (init) { + throw new Error('registerExtensionPoint called after registerInit'); + } + extensionPoints.push([ext, impl]); + }, + registerInit(regInit) { + if (init) { + throw new Error('registerInit must only be called once'); + } + init = { + deps: regInit.deps, + func: regInit.init, + }; + }, + }); + + if (!init) { + throw new Error( + `registerInit was not called by register in ${options.moduleId} module for ${options.pluginId}`, + ); + } + + return [ + { + type: 'module', + pluginId: options.pluginId, + moduleId: options.moduleId, + extensionPoints, + init, + }, + ]; + } + + function backendFeatureCompatWrapper() { + return backendFeatureCompatWrapper; + } + + Object.assign(backendFeatureCompatWrapper, { + $$type: '@backstage/BackendFeature' as const, + version: 'v1', + getRegistrations, + }); + + return backendFeatureCompatWrapper as BackendFeatureCompat; +} diff --git a/packages/backend-plugin-api/src/wiring/createBackendPlugin.test.ts b/packages/backend-plugin-api/src/wiring/createBackendPlugin.test.ts new file mode 100644 index 0000000000..db4d60ee19 --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createBackendPlugin.test.ts @@ -0,0 +1,55 @@ +/* + * 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 { createBackendPlugin } from './createBackendPlugin'; +import { InternalBackendRegistrations } from './types'; + +describe('createBackendPlugin', () => { + it('should create a BackendPlugin', () => { + const result = createBackendPlugin({ + pluginId: 'x', + register(r) { + r.registerInit({ deps: {}, async init() {} }); + }, + }); + + // legacy form + const legacy = result() as unknown as InternalBackendRegistrations; + expect(legacy.$$type).toEqual('@backstage/BackendFeature'); + expect(legacy.version).toEqual('v1'); + expect(legacy.getRegistrations).toEqual(expect.any(Function)); + + // new form + const plugin = result as unknown as InternalBackendRegistrations; + expect(plugin.$$type).toEqual('@backstage/BackendFeature'); + expect(plugin.version).toEqual('v1'); + expect(plugin.getRegistrations).toEqual(expect.any(Function)); + expect(plugin.getRegistrations()).toEqual([ + { + type: 'plugin', + pluginId: 'x', + extensionPoints: [], + init: { + deps: expect.any(Object), + func: expect.any(Function), + }, + }, + ]); + + // @ts-expect-error + expect(plugin({ a: 'a' })).toBeDefined(); + }); +}); diff --git a/packages/backend-plugin-api/src/wiring/createBackendPlugin.ts b/packages/backend-plugin-api/src/wiring/createBackendPlugin.ts new file mode 100644 index 0000000000..f5984ef24b --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createBackendPlugin.ts @@ -0,0 +1,100 @@ +/* + * 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 { BackendFeatureCompat } from '../types'; +import { + BackendPluginRegistrationPoints, + InternalBackendPluginRegistration, +} from './types'; + +/** + * The configuration options passed to {@link createBackendPlugin}. + * + * @public + * @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins} + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ +export interface CreateBackendPluginOptions { + /** + * The ID of this plugin. + * + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ + pluginId: string; + register(reg: BackendPluginRegistrationPoints): void; +} + +/** + * Creates a new backend plugin. + * + * @public + * @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins} + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ +export function createBackendPlugin( + options: CreateBackendPluginOptions, +): BackendFeatureCompat { + function getRegistrations() { + const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] = + []; + let init: InternalBackendPluginRegistration['init'] | undefined = undefined; + + options.register({ + registerExtensionPoint(ext, impl) { + if (init) { + throw new Error('registerExtensionPoint called after registerInit'); + } + extensionPoints.push([ext, impl]); + }, + registerInit(regInit) { + if (init) { + throw new Error('registerInit must only be called once'); + } + init = { + deps: regInit.deps, + func: regInit.init, + }; + }, + }); + + if (!init) { + throw new Error( + `registerInit was not called by register in ${options.pluginId}`, + ); + } + + return [ + { + type: 'plugin', + pluginId: options.pluginId, + extensionPoints, + init, + }, + ]; + } + + function backendFeatureCompatWrapper() { + return backendFeatureCompatWrapper; + } + + Object.assign(backendFeatureCompatWrapper, { + $$type: '@backstage/BackendFeature' as const, + version: 'v1', + getRegistrations, + }); + + return backendFeatureCompatWrapper as BackendFeatureCompat; +} diff --git a/packages/backend-plugin-api/src/wiring/createExtensionPoint.test.ts b/packages/backend-plugin-api/src/wiring/createExtensionPoint.test.ts new file mode 100644 index 0000000000..825063e845 --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createExtensionPoint.test.ts @@ -0,0 +1,27 @@ +/* + * 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 { createExtensionPoint } from './createExtensionPoint'; + +describe('createExtensionPoint', () => { + it('should create an ExtensionPoint', () => { + const extensionPoint = createExtensionPoint({ id: 'x' }); + expect(extensionPoint).toBeDefined(); + expect(extensionPoint.id).toBe('x'); + expect(() => extensionPoint.T).not.toThrow(); + expect(String(extensionPoint)).toBe('extensionPoint{x}'); + }); +}); diff --git a/packages/backend-plugin-api/src/wiring/createExtensionPoint.ts b/packages/backend-plugin-api/src/wiring/createExtensionPoint.ts new file mode 100644 index 0000000000..9dbae249ea --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/createExtensionPoint.ts @@ -0,0 +1,58 @@ +/* + * 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 { ExtensionPoint } from './types'; + +/** + * The configuration options passed to {@link createExtensionPoint}. + * + * @public + * @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points} + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ +export interface CreateExtensionPointOptions { + /** + * The ID of this extension point. + * + * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} + */ + id: string; +} + +/** + * Creates a new backend extension point. + * + * @public + * @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points} + */ +export function createExtensionPoint( + options: CreateExtensionPointOptions, +): ExtensionPoint { + return { + id: options.id, + get T(): T { + if (process.env.NODE_ENV === 'test') { + // Avoid throwing errors so tests asserting extensions' properties cannot be easily broken + return null as T; + } + throw new Error(`tried to read ExtensionPoint.T of ${this}`); + }, + toString() { + return `extensionPoint{${options.id}}`; + }, + $$type: '@backstage/ExtensionPoint', + }; +} diff --git a/packages/backend-plugin-api/src/wiring/describeParentCallSite.ts b/packages/backend-plugin-api/src/wiring/describeParentCallSite.ts new file mode 100644 index 0000000000..35603e33b0 --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/describeParentCallSite.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Single re-export to avoid doing this import in multiple places, but still +// avoid duplicate declarations because this one is a bit tricky. +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +export { describeParentCallSite } from '../../../frontend-plugin-api/src/routing/describeParentCallSite'; diff --git a/packages/backend-plugin-api/src/wiring/factories.test.ts b/packages/backend-plugin-api/src/wiring/factories.test.ts deleted file mode 100644 index 6d5c1f39cd..0000000000 --- a/packages/backend-plugin-api/src/wiring/factories.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - createBackendModule, - createBackendPlugin, - createExtensionPoint, -} from './factories'; -import { InternalBackendFeature } from './types'; - -describe('createExtensionPoint', () => { - it('should create an ExtensionPoint', () => { - const extensionPoint = createExtensionPoint({ id: 'x' }); - expect(extensionPoint).toBeDefined(); - expect(extensionPoint.id).toBe('x'); - expect(() => extensionPoint.T).not.toThrow(); - expect(String(extensionPoint)).toBe('extensionPoint{x}'); - }); -}); - -describe('createBackendPlugin', () => { - it('should create a BackendPlugin', () => { - const result = createBackendPlugin({ - pluginId: 'x', - register(r) { - r.registerInit({ deps: {}, async init() {} }); - }, - }); - - // legacy form - const legacy = result() as unknown as InternalBackendFeature; - expect(legacy.$$type).toEqual('@backstage/BackendFeature'); - expect(legacy.version).toEqual('v1'); - expect(legacy.getRegistrations).toEqual(expect.any(Function)); - - // new form - const plugin = result as unknown as InternalBackendFeature; - expect(plugin.$$type).toEqual('@backstage/BackendFeature'); - expect(plugin.version).toEqual('v1'); - expect(plugin.getRegistrations).toEqual(expect.any(Function)); - expect(plugin.getRegistrations()).toEqual([ - { - type: 'plugin', - pluginId: 'x', - extensionPoints: [], - init: { - deps: expect.any(Object), - func: expect.any(Function), - }, - }, - ]); - - // @ts-expect-error - expect(plugin({ a: 'a' })).toBeDefined(); - }); -}); - -describe('createBackendModule', () => { - it('should create a BackendModule', () => { - const result = createBackendModule({ - pluginId: 'x', - moduleId: 'y', - register(r) { - r.registerInit({ deps: {}, async init() {} }); - }, - }); - - // legacy form - const legacy = result() as unknown as InternalBackendFeature; - expect(legacy.$$type).toEqual('@backstage/BackendFeature'); - expect(legacy.version).toEqual('v1'); - expect(legacy.getRegistrations).toEqual(expect.any(Function)); - - // new form - const module = result as unknown as InternalBackendFeature; - expect(module.$$type).toEqual('@backstage/BackendFeature'); - expect(module.version).toEqual('v1'); - expect(module.getRegistrations).toEqual(expect.any(Function)); - expect(module.getRegistrations()).toEqual([ - { - type: 'module', - pluginId: 'x', - moduleId: 'y', - extensionPoints: [], - init: { - deps: expect.any(Object), - func: expect.any(Function), - }, - }, - ]); - - // @ts-expect-error - expect(module({ a: 'a' })).toBeDefined(); - }); -}); diff --git a/packages/backend-plugin-api/src/wiring/factories.ts b/packages/backend-plugin-api/src/wiring/factories.ts deleted file mode 100644 index 81e2247152..0000000000 --- a/packages/backend-plugin-api/src/wiring/factories.ts +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { BackendFeatureCompat } from '../types'; -import { - BackendModuleRegistrationPoints, - BackendPluginRegistrationPoints, - ExtensionPoint, - InternalBackendModuleRegistration, - InternalBackendPluginRegistration, -} from './types'; - -/** - * The configuration options passed to {@link createExtensionPoint}. - * - * @public - * @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points} - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ -export interface CreateExtensionPointOptions { - /** - * The ID of this extension point. - * - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ - id: string; -} - -/** - * Creates a new backend extension point. - * - * @public - * @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points} - */ -export function createExtensionPoint( - options: CreateExtensionPointOptions, -): ExtensionPoint { - return { - id: options.id, - get T(): T { - if (process.env.NODE_ENV === 'test') { - // Avoid throwing errors so tests asserting extensions' properties cannot be easily broken - return null as T; - } - throw new Error(`tried to read ExtensionPoint.T of ${this}`); - }, - toString() { - return `extensionPoint{${options.id}}`; - }, - $$type: '@backstage/ExtensionPoint', - }; -} - -/** - * The configuration options passed to {@link createBackendPlugin}. - * - * @public - * @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins} - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ -export interface CreateBackendPluginOptions { - /** - * The ID of this plugin. - * - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ - pluginId: string; - register(reg: BackendPluginRegistrationPoints): void; -} - -/** - * Creates a new backend plugin. - * - * @public - * @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins} - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ -export function createBackendPlugin( - options: CreateBackendPluginOptions, -): BackendFeatureCompat { - function getRegistrations() { - const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] = - []; - let init: InternalBackendPluginRegistration['init'] | undefined = undefined; - - options.register({ - registerExtensionPoint(ext, impl) { - if (init) { - throw new Error('registerExtensionPoint called after registerInit'); - } - extensionPoints.push([ext, impl]); - }, - registerInit(regInit) { - if (init) { - throw new Error('registerInit must only be called once'); - } - init = { - deps: regInit.deps, - func: regInit.init, - }; - }, - }); - - if (!init) { - throw new Error( - `registerInit was not called by register in ${options.pluginId}`, - ); - } - - return [ - { - type: 'plugin', - pluginId: options.pluginId, - extensionPoints, - init, - }, - ]; - } - - function backendFeatureCompatWrapper() { - return backendFeatureCompatWrapper; - } - - Object.assign(backendFeatureCompatWrapper, { - $$type: '@backstage/BackendFeature' as const, - version: 'v1', - getRegistrations, - }); - - return backendFeatureCompatWrapper as BackendFeatureCompat; -} - -/** - * The configuration options passed to {@link createBackendModule}. - * - * @public - * @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules} - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ -export interface CreateBackendModuleOptions { - /** - * Should exactly match the `id` of the plugin that the module extends. - * - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ - pluginId: string; - - /** - * The ID of this module, used to identify the module and ensure that it is not installed twice. - */ - moduleId: string; - register(reg: BackendModuleRegistrationPoints): void; -} - -/** - * Creates a new backend module for a given plugin. - * - * @public - * @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules} - * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} - */ -export function createBackendModule( - options: CreateBackendModuleOptions, -): BackendFeatureCompat { - function getRegistrations() { - const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] = - []; - let init: InternalBackendModuleRegistration['init'] | undefined = undefined; - - options.register({ - registerExtensionPoint(ext, impl) { - if (init) { - throw new Error('registerExtensionPoint called after registerInit'); - } - extensionPoints.push([ext, impl]); - }, - registerInit(regInit) { - if (init) { - throw new Error('registerInit must only be called once'); - } - init = { - deps: regInit.deps, - func: regInit.init, - }; - }, - }); - - if (!init) { - throw new Error( - `registerInit was not called by register in ${options.moduleId} module for ${options.pluginId}`, - ); - } - - return [ - { - type: 'module', - pluginId: options.pluginId, - moduleId: options.moduleId, - extensionPoints, - init, - }, - ]; - } - - function backendFeatureCompatWrapper() { - return backendFeatureCompatWrapper; - } - - Object.assign(backendFeatureCompatWrapper, { - $$type: '@backstage/BackendFeature' as const, - version: 'v1', - getRegistrations, - }); - - return backendFeatureCompatWrapper as BackendFeatureCompat; -} diff --git a/packages/backend-plugin-api/src/wiring/index.ts b/packages/backend-plugin-api/src/wiring/index.ts index 5197cec050..95eea6c3d4 100644 --- a/packages/backend-plugin-api/src/wiring/index.ts +++ b/packages/backend-plugin-api/src/wiring/index.ts @@ -14,17 +14,17 @@ * limitations under the License. */ -import type { - CreateBackendPluginOptions, - CreateBackendModuleOptions, - CreateExtensionPointOptions, -} from './factories'; +import { type CreateBackendModuleOptions } from './createBackendModule'; +import { type CreateBackendPluginOptions } from './createBackendPlugin'; +import { type CreateExtensionPointOptions } from './createExtensionPoint'; +export { createBackendModule } from './createBackendModule'; +export { createBackendPlugin } from './createBackendPlugin'; +export { createExtensionPoint } from './createExtensionPoint'; export { - createBackendModule, - createBackendPlugin, - createExtensionPoint, -} from './factories'; + createBackendFeatureLoader, + type CreateBackendFeatureLoaderOptions, +} from './createBackendFeatureLoader'; export type { BackendModuleRegistrationPoints, diff --git a/packages/backend-plugin-api/src/wiring/types.ts b/packages/backend-plugin-api/src/wiring/types.ts index 55d43ccb7c..01ab8c2e3e 100644 --- a/packages/backend-plugin-api/src/wiring/types.ts +++ b/packages/backend-plugin-api/src/wiring/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ServiceRef } from '../services/system/types'; +import { InternalServiceFactory, ServiceRef } from '../services/system/types'; import { BackendFeature } from '../types'; /** @@ -73,8 +73,9 @@ export interface BackendModuleRegistrationPoints { } /** @internal */ -export interface InternalBackendFeature extends BackendFeature { +export interface InternalBackendRegistrations extends BackendFeature { version: 'v1'; + featureType: 'registrations'; getRegistrations(): Array< InternalBackendPluginRegistration | InternalBackendModuleRegistration >; @@ -102,3 +103,20 @@ export interface InternalBackendModuleRegistration { func(deps: Record): Promise; }; } + +/** + * @public + */ +export interface InternalBackendFeatureLoader extends BackendFeature { + version: 'v1'; + featureType: 'loader'; + description: string; + deps: Record>; + loader(deps: Record): Promise; +} + +/** @internal */ +export type InternalBackendFeature = + | InternalBackendRegistrations + | InternalBackendFeatureLoader + | InternalServiceFactory; diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 590d824635..1a5879f14e 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/backend-tasks +## 0.5.28-next.2 + +### Patch Changes + +- ba9abf4: The `PluginTaskScheduler` now allows tasks with `frequency: { trigger: 'manual' }`. This means that the task will not be scheduled, but rather run only when manually triggered with `PluginTaskScheduler.triggerTask`. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.5.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.5.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.5.27 + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.5.27-next.1 ### Patch Changes diff --git a/packages/backend-tasks/api-report.md b/packages/backend-tasks/api-report.md index 0d5ced044a..c0f9da3a01 100644 --- a/packages/backend-tasks/api-report.md +++ b/packages/backend-tasks/api-report.md @@ -62,7 +62,14 @@ export interface TaskScheduleDefinition { cron: string; } | Duration - | HumanDuration_2; + | HumanDuration_2 + /** + * This task will only run when manually triggered with the `triggerTask` method; no automatic + * scheduling. This is useful for locking of global tasks that should not be run concurrently. + */ + | { + trigger: 'manual'; + }; initialDelay?: Duration | HumanDuration_2; scope?: 'global' | 'local'; timeout: Duration | HumanDuration_2; diff --git a/packages/backend-tasks/migrations/20240712211735_nullable_next_run.js b/packages/backend-tasks/migrations/20240712211735_nullable_next_run.js new file mode 100644 index 0000000000..efbef1c76f --- /dev/null +++ b/packages/backend-tasks/migrations/20240712211735_nullable_next_run.js @@ -0,0 +1,41 @@ +/* + * 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. + */ + +// @ts-check + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = async function up(knex) { + await knex.schema.alterTable('backstage_backend_tasks__tasks', table => { + table.setNullable('next_run_start_at'); + }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = async function down(knex) { + await knex + .delete() + .from('backstage_backend_tasks__tasks') + .where({ next_run_start_at: null }); + await knex.schema.alterTable('backstage_backend_tasks__tasks', table => { + table.dropNullable('next_run_start_at'); + }); +}; diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index df10190443..3f482b38e6 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.5.27-next.1", + "version": "0.5.28-next.2", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-tasks/src/migrations.test.ts b/packages/backend-tasks/src/migrations.test.ts index 82208da975..7583948f71 100644 --- a/packages/backend-tasks/src/migrations.test.ts +++ b/packages/backend-tasks/src/migrations.test.ts @@ -81,4 +81,43 @@ describe('migrations', () => { await knex.destroy(); }, ); + + it.each(databases.eachSupportedId())( + '20240712211735_nullable_next_run.js, %p', + async databaseId => { + const knex = await databases.init(databaseId); + + await migrateUntilBefore(knex, '20240712211735_nullable_next_run.js'); + await migrateUpOnce(knex); + + await knex('backstage_backend_tasks__tasks').insert({ + id: 'test', + settings_json: '{}', + next_run_start_at: knex.raw('null'), + }); + + await expect(knex('backstage_backend_tasks__tasks')).resolves.toEqual([ + { + id: 'test', + settings_json: '{}', + next_run_start_at: null, + current_run_ticket: null, + current_run_started_at: null, + current_run_expires_at: null, + }, + ]); + + await migrateDownOnce(knex); + + await expect( + knex('backstage_backend_tasks__tasks').insert({ + id: 'test', + settings_json: '{}', + next_run_start_at: knex.raw('null'), + }), + ).rejects.toEqual(expect.anything()); + + await knex.destroy(); + }, + ); }); diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts index 77965632e9..eca899098f 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts @@ -345,6 +345,7 @@ describe('PluginTaskManagerImpl', () => { expect(parseDuration({ milliseconds: 5000 })).toEqual('PT5S'); expect(parseDuration(Duration.fromMillis(5000))).toEqual('PT5S'); expect(parseDuration({ cron: '1 * * * *' })).toEqual('1 * * * *'); + expect(parseDuration({ trigger: 'manual' })).toEqual('manual'); }); }); }); diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts index b1647f4edf..0ccc77a6c1 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts @@ -152,6 +152,9 @@ export function parseDuration( if ('cron' in frequency) { return frequency.cron; } + if ('trigger' in frequency) { + return frequency.trigger; + } const parsed = Duration.isDuration(frequency) ? frequency diff --git a/packages/backend-tasks/src/tasks/TaskWorker.test.ts b/packages/backend-tasks/src/tasks/TaskWorker.test.ts index 10ebfde5b4..829d7754f8 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.test.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.test.ts @@ -503,4 +503,32 @@ describe('TaskWorker', () => { await knex.destroy(); }, ); + + it.each(databases.eachSupportedId())( + 'next_run_start_at is not set for manually-triggered tasks, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn( + async () => new Promise(resolve => setTimeout(resolve, 50)), + ); + + const initialSettings: TaskSettingsV2 = { + version: 2, + cadence: 'manual', + timeoutAfterDuration: 'PT1M', + }; + + const worker = new TaskWorker('task99', fn, knex, logger); + await worker.persistTask(initialSettings); + await worker.tryClaimTask('ticket', initialSettings); + await worker.tryReleaseTask('ticket', initialSettings); + + const row = (await knex(DB_TASKS_TABLE))[0]; + expect(row.next_run_start_at).toBeNull(); + + await knex.destroy(); + }, + ); }); diff --git a/packages/backend-tasks/src/tasks/TaskWorker.ts b/packages/backend-tasks/src/tasks/TaskWorker.ts index 57cbf2203e..a50b988522 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.ts @@ -52,8 +52,8 @@ export class TaskWorker { ); let workCheckFrequency = this.workCheckFrequency; - const isCron = !settings?.cadence.startsWith('P'); - if (!isCron) { + const isDuration = settings?.cadence.startsWith('P'); + if (isDuration) { const cadence = Duration.fromISO(settings.cadence); if (cadence < workCheckFrequency) { workCheckFrequency = cadence; @@ -174,7 +174,9 @@ export class TaskWorker { // read it back again. taskSettingsV2Schema.parse(settings); - const isCron = !settings?.cadence.startsWith('P'); + const isManual = settings?.cadence === 'manual'; + const isDuration = settings?.cadence.startsWith('P'); + const isCron = !isManual && !isDuration; let startAt: Knex.Raw | undefined; let nextStartAt: Knex.Raw | undefined; @@ -193,6 +195,9 @@ export class TaskWorker { nextStartAt = this.nextRunAtRaw(time); startAt ||= nextStartAt; + } else if (isManual) { + nextStartAt = this.knex.raw('null'); + startAt ||= nextStartAt; } else { startAt ||= this.knex.fn.now(); nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex); @@ -316,7 +321,9 @@ export class TaskWorker { ticket: string, settings: TaskSettingsV2, ): Promise { - const isCron = !settings?.cadence.startsWith('P'); + const isManual = settings?.cadence === 'manual'; + const isDuration = settings?.cadence.startsWith('P'); + const isCron = !isManual && !isDuration; let nextRun: Knex.Raw; if (isCron) { @@ -324,6 +331,8 @@ export class TaskWorker { this.logger.debug(`task: ${this.taskId} will next occur around ${time}`); nextRun = this.nextRunAtRaw(time); + } else if (isManual) { + nextRun = this.knex.raw('null'); } else { const dt = Duration.fromISO(settings.cadence).as('seconds'); this.logger.debug( diff --git a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts index e94d06d5c3..85099d82db 100644 --- a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts +++ b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts @@ -32,14 +32,20 @@ function readDuration(config: Config, key: string): HumanDuration { return readDurationFromConfig(config, { key }); } -function readCronOrDuration( +function readFrequency( config: Config, key: string, -): { cron: string } | Duration | HumanDuration { +): { cron: string } | Duration | HumanDuration | { trigger: 'manual' } { const value = config.get(key); if (typeof value === 'object' && (value as { cron?: string }).cron) { return value as { cron: string }; } + if ( + typeof value === 'object' && + (value as { trigger?: string }).trigger === 'manual' + ) { + return { trigger: 'manual' }; + } return readDuration(config, key); } @@ -56,7 +62,7 @@ function readCronOrDuration( export function readTaskScheduleDefinitionFromConfig( config: Config, ): TaskScheduleDefinition { - const frequency = readCronOrDuration(config, 'frequency'); + const frequency = readFrequency(config, 'frequency'); const timeout = readDuration(config, 'timeout'); const initialDelay = config.has('initialDelay') diff --git a/packages/backend-tasks/src/tasks/types.ts b/packages/backend-tasks/src/tasks/types.ts index e6a31873be..a0bdbbaa64 100644 --- a/packages/backend-tasks/src/tasks/types.ts +++ b/packages/backend-tasks/src/tasks/types.ts @@ -100,7 +100,12 @@ export interface TaskScheduleDefinition { cron: string; } | Duration - | HumanDuration; + | HumanDuration + /** + * This task will only run when manually triggered with the `triggerTask` method; no automatic + * scheduling. This is useful for locking of global tasks that should not be run concurrently. + */ + | { trigger: 'manual' }; /** * The maximum amount of time that a single task invocation can take, before @@ -373,6 +378,10 @@ function isValidCronFormat(c: string | undefined): boolean { } } +function isValidTrigger(t: string): boolean { + return t === 'manual'; +} + export const taskSettingsV1Schema = z.object({ version: z.literal(1), initialDelayDuration: z @@ -401,6 +410,11 @@ export const taskSettingsV2Schema = z.object({ cadence: z .string() .refine(isValidCronFormat, { message: 'Invalid cron' }) + .or( + z.string().refine(isValidTrigger, { + message: "Invalid trigger, expecting 'manual'", + }), + ) .or( z.string().refine(isValidOptionalDurationString, { message: 'Invalid duration, expecting ISO Period', diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 9f3d84a906..cbca6bdcab 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,72 @@ # @backstage/backend-test-utils +## 0.4.5-next.2 + +### Patch Changes + +- 8b13183: Internal updates to support latest version of `BackendFeauture`s from `@backstage/backend-plugin-api`. +- 7c5f3b0: Update the `ServiceFactoryTester` to be able to test services that enables multi implementation installation. +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.2 + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-app-api@0.8.1-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-app-api@0.8.1-next.1 + - @backstage/backend-defaults@0.4.2-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.4.5-next.0 + +### Patch Changes + +- 4e79d19: The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service. +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.4.4 + +### Patch Changes + +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- edf5cc3: The function `isDockerDisabledForTests` is deprecated and will no longer be exported in the near future as it should only be used internally. +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- fce7887: Added mock for the Root Health Service in `mockServices`. +- 906c817: Updated `startTestBackend` and `ServiceFactoryTester` to only accept plain service factory or backend feature objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes. +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- 98ccf00: Internal refactor of `mockServices.httpAuth.factory` to allow it to still be constructed with options, but without declaring options via `createServiceFactory`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.4-next.1 ### Patch Changes diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index d3a618d214..584fedb1f5 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,12 @@ export namespace mockServices { // (undocumented) export namespace auth { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + AuthService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -164,7 +170,12 @@ export namespace mockServices { // (undocumented) export namespace cache { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + CacheService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -173,7 +184,12 @@ export namespace mockServices { // (undocumented) export namespace database { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + DatabaseService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -184,7 +200,12 @@ export namespace mockServices { // (undocumented) export namespace discovery { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + DiscoveryService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -193,7 +214,12 @@ export namespace mockServices { // (undocumented) export namespace events { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + EventsService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -205,13 +231,10 @@ export namespace mockServices { }): HttpAuthService; // (undocumented) export namespace httpAuth { - const factory: ( - options?: - | { - defaultCredentials?: BackstageCredentials | undefined; - } - | undefined, - ) => ServiceFactory; + const factory: ((options?: { + defaultCredentials?: BackstageCredentials; + }) => ServiceFactory) & + ServiceFactory; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -220,7 +243,12 @@ export namespace mockServices { // (undocumented) export namespace httpRouter { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + HttpRouterService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -231,7 +259,12 @@ export namespace mockServices { // (undocumented) export namespace identity { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + IdentityService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -240,7 +273,12 @@ export namespace mockServices { // (undocumented) export namespace lifecycle { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + LifecycleService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -249,7 +287,12 @@ export namespace mockServices { // (undocumented) export namespace logger { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + LoggerService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -258,7 +301,12 @@ export namespace mockServices { // (undocumented) export namespace permissions { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + PermissionsService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -273,14 +321,28 @@ export namespace mockServices { data?: JsonObject; }; const // (undocumented) - factory: ( - options?: Options | undefined, - ) => ServiceFactory; + factory: ServiceFactory< + RootConfigService, + 'root', + 'singleton' | 'multiton' + > & + (( + options?: Options | undefined, + ) => ServiceFactory< + RootConfigService, + 'root', + 'singleton' | 'multiton' + >); } // (undocumented) export namespace rootHealth { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + RootHealthService, + 'root', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -289,9 +351,10 @@ export namespace mockServices { // (undocumented) export namespace rootHttpRouter { const // (undocumented) - factory: ( + factory: (( options?: RootHttpRouterFactoryOptions | undefined, - ) => ServiceFactory; + ) => ServiceFactory) & + ServiceFactory; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -300,7 +363,12 @@ export namespace mockServices { // (undocumented) export namespace rootLifecycle { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + RootLifecycleService, + 'root', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -315,9 +383,10 @@ export namespace mockServices { level?: 'none' | 'error' | 'warn' | 'info' | 'debug'; }; const // (undocumented) - factory: ( - options?: Options | undefined, - ) => ServiceFactory; + factory: ServiceFactory & + (( + options?: Options | undefined, + ) => ServiceFactory); const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -326,7 +395,12 @@ export namespace mockServices { // (undocumented) export namespace scheduler { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + SchedulerService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -337,7 +411,12 @@ export namespace mockServices { // (undocumented) export namespace tokenManager { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + TokenManagerService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -346,7 +425,12 @@ export namespace mockServices { // (undocumented) export namespace urlReader { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat< + UrlReaderService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -357,7 +441,12 @@ export namespace mockServices { ): UserInfoService; // (undocumented) export namespace userInfo { - const factory: () => ServiceFactory; + const factory: ServiceFactoryCompat< + UserInfoService, + 'plugin', + 'singleton', + undefined + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -366,29 +455,46 @@ export namespace mockServices { } // @public -export class ServiceFactoryTester { - static from( - subject: - | ServiceFactory - | (() => ServiceFactory), +export function registerMswTestHooks(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void; + +// @public +export class ServiceFactoryTester< + TService, + TScope extends 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton' = 'singleton', +> { + static from< + TService, + TScope extends 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton' = 'singleton', + >( + subject: ServiceFactory, options?: ServiceFactoryTesterOptions, - ): ServiceFactoryTester; + ): ServiceFactoryTester; // @deprecated get( ...args: 'root' extends TScope ? [] : [pluginId?: string] - ): Promise; - getService( - service: ServiceRef, + ): Promise; + getService< + TGetService, + TGetScope extends 'root' | 'plugin', + TGetInstances extends 'singleton' | 'multiton' = 'singleton', + >( + service: ServiceRef, ...args: 'root' extends TGetScope ? [] : [pluginId?: string] - ): Promise; + ): Promise; getSubject( ...args: 'root' extends TScope ? [] : [pluginId?: string] - ): Promise; + ): Promise; } // @public export interface ServiceFactoryTesterOptions { - dependencies?: Array ServiceFactory)>; + dependencies?: Array; } // @public (undocumented) @@ -402,7 +508,7 @@ export type ServiceMock = { : TService[Key]; }; -// @public +// @public @deprecated (undocumented) export function setupRequestMockHandlers(worker: { listen: (t: any) => void; close: () => void; @@ -433,9 +539,8 @@ export interface TestBackendOptions { // (undocumented) features?: Array< | BackendFeature - | (() => BackendFeature) | Promise<{ - default: BackendFeature | (() => BackendFeature); + default: BackendFeature; }> >; } diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index e975dc01d9..44373e733f 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-test-utils", - "version": "0.4.4-next.1", + "version": "0.4.5-next.2", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend-test-utils/src/deprecated.ts b/packages/backend-test-utils/src/deprecated.ts index 5fe74e7ef3..9790580a9c 100644 --- a/packages/backend-test-utils/src/deprecated.ts +++ b/packages/backend-test-utils/src/deprecated.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { registerMswTestHooks } from './msw'; import { CreateMockDirectoryOptions } from './filesystem'; import { isDockerDisabledForTests as _isDockerDisabledForTests } from './util'; @@ -23,6 +24,18 @@ import { isDockerDisabledForTests as _isDockerDisabledForTests } from './util'; */ export type MockDirectoryOptions = CreateMockDirectoryOptions; +/** + * @public + * @deprecated Use `registerMswTestHooks` from `@backstage/backend-test-utils` instead. + */ +export function setupRequestMockHandlers(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void { + registerMswTestHooks(worker); +} + /** * @public * @deprecated This is an internal function and will no longer be exported from this package. diff --git a/packages/backend-test-utils/src/msw/index.ts b/packages/backend-test-utils/src/msw/index.ts index 29cbdf854a..fa6a37445f 100644 --- a/packages/backend-test-utils/src/msw/index.ts +++ b/packages/backend-test-utils/src/msw/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { setupRequestMockHandlers } from './setupRequestMockHandlers'; +export { registerMswTestHooks } from './registerMswTestHooks'; diff --git a/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts b/packages/backend-test-utils/src/msw/registerMswTestHooks.ts similarity index 94% rename from packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts rename to packages/backend-test-utils/src/msw/registerMswTestHooks.ts index 625ef0e0fc..4e26c38321 100644 --- a/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts +++ b/packages/backend-test-utils/src/msw/registerMswTestHooks.ts @@ -19,7 +19,7 @@ * @public * @param worker - service worker */ -export function setupRequestMockHandlers(worker: { +export function registerMswTestHooks(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index d56179d958..8d36fec50e 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -70,21 +70,28 @@ function createLoggerMock() { } /** @internal */ -function simpleFactory< +function simpleFactoryWithOptions< TService, TScope extends 'root' | 'plugin', TOptions extends [options?: object] = [], >( ref: ServiceRef, factory: (...options: TOptions) => TService, -): (...options: TOptions) => ServiceFactory { - return createServiceFactory((options: unknown) => ({ - service: ref as ServiceRef, - deps: {}, - async factory() { - return (factory as any)(options); - }, - })) as (...options: TOptions) => ServiceFactory; +): ServiceFactory & + ((...options: TOptions) => ServiceFactory) { + const factoryWithOptions = (...options: TOptions) => + createServiceFactory({ + service: ref as ServiceRef, + deps: {}, + async factory() { + return factory(...options); + }, + })(); + return Object.assign( + factoryWithOptions, + factoryWithOptions(...([undefined] as unknown as TOptions)), + ) as ServiceFactory & + ((...options: TOptions) => ServiceFactory); } /** @public */ @@ -134,7 +141,10 @@ export namespace mockServices { export namespace rootConfig { export type Options = { data?: JsonObject }; - export const factory = simpleFactory(coreServices.rootConfig, rootConfig); + export const factory = simpleFactoryWithOptions( + coreServices.rootConfig, + rootConfig, + ); } export function rootLogger(options?: rootLogger.Options): LoggerService { @@ -145,7 +155,10 @@ export namespace mockServices { level?: 'none' | 'error' | 'warn' | 'info' | 'debug'; }; - export const factory = simpleFactory(coreServices.rootLogger, rootLogger); + export const factory = simpleFactoryWithOptions( + coreServices.rootLogger, + rootLogger, + ); export const mock = simpleMock(coreServices.rootLogger, () => ({ child: jest.fn(), debug: jest.fn(), @@ -168,10 +181,11 @@ export namespace mockServices { }; } export namespace tokenManager { - export const factory = simpleFactory( - coreServices.tokenManager, - tokenManager, - ); + export const factory = createServiceFactory({ + service: coreServices.tokenManager, + deps: {}, + factory: () => tokenManager(), + }); export const mock = simpleMock(coreServices.tokenManager, () => ({ authenticate: jest.fn(), getToken: jest.fn(), @@ -182,7 +196,11 @@ export namespace mockServices { return new MockIdentityService(); } export namespace identity { - export const factory = simpleFactory(coreServices.identity, identity); + export const factory = createServiceFactory({ + service: coreServices.identity, + deps: {}, + factory: () => identity(), + }); export const mock = simpleMock(coreServices.identity, () => ({ getIdentity: jest.fn(), })); @@ -270,15 +288,10 @@ export namespace mockServices { ); } export namespace httpAuth { - /** - * Creates a mock service factory for the `HttpAuthService`. - * - * By default all requests without credentials are treated as requests from - * the default mock user principal. This behavior can be configured with the - * `defaultCredentials` option. - */ - export const factory = createServiceFactory( - (options?: { defaultCredentials?: BackstageCredentials }) => ({ + const factoryWithOptions = (options?: { + defaultCredentials?: BackstageCredentials; + }) => + createServiceFactory({ service: coreServices.httpAuth, deps: { plugin: coreServices.pluginMetadata }, factory: ({ plugin }) => @@ -286,7 +299,17 @@ export namespace mockServices { plugin.getId(), options?.defaultCredentials ?? mockCredentials.user(), ), - }), + })(); + /** + * Creates a mock service factory for the `HttpAuthService`. + * + * By default all requests without credentials are treated as requests from + * the default mock user principal. This behavior can be configured with the + * `defaultCredentials` option. + */ + export const factory = Object.assign( + factoryWithOptions, + factoryWithOptions(), ); export const mock = simpleMock(coreServices.httpAuth, () => ({ credentials: jest.fn(), diff --git a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts index 40b473663b..e8530f89bf 100644 --- a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts +++ b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts @@ -35,7 +35,7 @@ export interface ServiceFactoryTesterOptions { * If a service factory is provided for a service that already has a default * implementation, the provided factory will override the default. */ - dependencies?: Array ServiceFactory)>; + dependencies?: Array; } /** @@ -43,8 +43,12 @@ export interface ServiceFactoryTesterOptions { * * @public */ -export class ServiceFactoryTester { - readonly #subject: ServiceRef; +export class ServiceFactoryTester< + TService, + TScope extends 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton' = 'singleton', +> { + readonly #subject: ServiceRef; readonly #registry: ServiceRegistry; /** @@ -54,25 +58,24 @@ export class ServiceFactoryTester { * @param options - Additional options * @returns A new tester instance for the provided subject. */ - static from( - subject: - | ServiceFactory - | (() => ServiceFactory), + static from< + TService, + TScope extends 'root' | 'plugin', + TInstances extends 'singleton' | 'multiton' = 'singleton', + >( + subject: ServiceFactory, options?: ServiceFactoryTesterOptions, - ) { - const subjectFactory = typeof subject === 'function' ? subject() : subject; + ): ServiceFactoryTester { const registry = ServiceRegistry.create([ ...defaultServiceFactories, - ...(options?.dependencies?.map(f => - typeof f === 'function' ? f() : f, - ) ?? []), - subjectFactory, + ...(options?.dependencies ?? []), + subject, ]); - return new ServiceFactoryTester(subjectFactory.service, registry); + return new ServiceFactoryTester(subject.service, registry); } private constructor( - subject: ServiceRef, + subject: ServiceRef, registry: ServiceRegistry, ) { this.#subject = subject; @@ -86,7 +89,7 @@ export class ServiceFactoryTester { */ async get( ...args: 'root' extends TScope ? [] : [pluginId?: string] - ): Promise { + ): Promise { return this.getSubject(...args); } @@ -102,9 +105,10 @@ export class ServiceFactoryTester { */ async getSubject( ...args: 'root' extends TScope ? [] : [pluginId?: string] - ): Promise { + ): Promise { const [pluginId] = args; - return this.#registry.get(this.#subject, pluginId ?? 'test')!; + const instance = this.#registry.get(this.#subject, pluginId ?? 'test')!; + return instance; } /** @@ -114,10 +118,14 @@ export class ServiceFactoryTester { * * A plugin ID can optionally be provided for plugin scoped services, otherwise the plugin ID 'test' is used. */ - async getService( - service: ServiceRef, + async getService< + TGetService, + TGetScope extends 'root' | 'plugin', + TGetInstances extends 'singleton' | 'multiton' = 'singleton', + >( + service: ServiceRef, ...args: 'root' extends TGetScope ? [] : [pluginId?: string] - ): Promise { + ): Promise { const [pluginId] = args; const instance = await this.#registry.get(service, pluginId ?? 'test'); if (instance === undefined) { diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts index ecba34290d..a01d4bebf5 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -242,6 +242,15 @@ describe('TestBackend', () => { expect(res.body).toEqual({ message: 'pong' }); }); + it('should expose health check endpoints', async () => { + const { server } = await startTestBackend({ features: [] }); + + const res = await request(server).get('/.backstage/health/v1/liveness'); + + expect(res.status).toEqual(200); + expect(res.body).toEqual({ status: 'ok' }); + }); + it('should provide extension point implementations', async () => { expect.assertions(3); diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index f23883ba3e..cf98c25e4a 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -36,7 +36,11 @@ import { ConfigReader } from '@backstage/config'; import express from 'express'; // Direct internal import to avoid duplication // eslint-disable-next-line @backstage/no-forbidden-package-imports -import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types'; +import { + InternalBackendFeature, + InternalBackendRegistrations, +} from '@backstage/backend-plugin-api/src/wiring/types'; +import { createHealthRouter } from '@backstage/backend-defaults/rootHttpRouter'; /** @public */ export interface TestBackendOptions { @@ -48,11 +52,7 @@ export interface TestBackendOptions { ]; }, ]; - features?: Array< - | BackendFeature - | (() => BackendFeature) - | Promise<{ default: BackendFeature | (() => BackendFeature) }> - >; + features?: Array>; } /** @public */ @@ -77,6 +77,7 @@ export const defaultServiceFactories = [ mockServices.lifecycle.factory(), mockServices.logger.factory(), mockServices.permissions.factory(), + mockServices.rootHealth.factory(), mockServices.rootLifecycle.factory(), mockServices.rootLogger.factory(), mockServices.scheduler.factory(), @@ -96,7 +97,7 @@ function createPluginsForOrphanModules(features: Array) { const modulePluginIds = new Set(); for (const feature of features) { - if (isInternalBackendFeature(feature)) { + if (isInternalBackendRegistrations(feature)) { const registrations = feature.getRegistrations(); for (const registration of registrations) { if (registration.type === 'plugin') { @@ -139,18 +140,7 @@ function createExtensionPointTestModules( } const registrations = features.flatMap(feature => { - if (feature.$$type !== '@backstage/BackendFeature') { - throw new Error( - `Failed to add feature, invalid type '${feature.$$type}'`, - ); - } - - if (isInternalBackendFeature(feature)) { - if (feature.version !== 'v1') { - throw new Error( - `Failed to add feature, invalid version '${feature.version}'`, - ); - } + if (isInternalBackendRegistrations(feature)) { return feature.getRegistrations(); } return []; @@ -255,15 +245,18 @@ export async function startTestBackend( config: coreServices.rootConfig, lifecycle: coreServices.rootLifecycle, rootLogger: coreServices.rootLogger, + health: coreServices.rootHealth, }, - async factory({ config, lifecycle, rootLogger }) { + async factory({ config, lifecycle, rootLogger, health }) { const router = DefaultRootHttpRouter.create(); const logger = rootLogger.child({ service: 'rootHttpRouter' }); const app = express(); const middleware = MiddlewareFactory.create({ config, logger }); + const healthRouter = createHealthRouter({ health }); + app.use(healthRouter); app.use(router.handler()); app.use(middleware.notFound()); app.use(middleware.error()); @@ -360,10 +353,28 @@ function registerTestHooks() { registerTestHooks(); -function isInternalBackendFeature( +function toInternalBackendFeature( feature: BackendFeature, -): feature is InternalBackendFeature { - return ( - typeof (feature as InternalBackendFeature).getRegistrations === 'function' - ); +): InternalBackendFeature { + if (feature.$$type !== '@backstage/BackendFeature') { + throw new Error(`Invalid BackendFeature, bad type '${feature.$$type}'`); + } + const internal = feature as InternalBackendFeature; + if (internal.version !== 'v1') { + throw new Error( + `Invalid BackendFeature, bad version '${internal.version}'`, + ); + } + return internal; +} + +function isInternalBackendRegistrations( + feature: BackendFeature, +): feature is InternalBackendRegistrations { + const internal = toInternalBackendFeature(feature); + if (internal.featureType === 'registrations') { + return true; + } + // Backwards compatibility for v1 registrations that use duck typing + return 'getRegistrations' in internal; } diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 4ceb786f2a..8fbce11752 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,153 @@ # example-backend +## 0.0.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.2 + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-backend@1.23.1-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.2 + - @backstage/plugin-notifications-backend@0.3.4-next.2 + - @backstage/plugin-kubernetes-backend@0.18.4-next.2 + - @backstage/plugin-permission-backend@0.5.47-next.2 + - @backstage/plugin-devtools-backend@0.3.9-next.2 + - @backstage/plugin-techdocs-backend@1.10.10-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-signals-backend@0.1.9-next.2 + - @backstage/plugin-proxy-backend@0.5.4-next.2 + - @backstage/plugin-auth-backend@0.22.10-next.2 + - @backstage/plugin-app-backend@0.3.72-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-search-backend-node@1.2.28-next.2 + - @backstage/plugin-search-backend@1.5.15-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.2 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.2 + - @backstage/catalog-model@1.5.0 + +## 0.0.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.1 + - @backstage/plugin-techdocs-backend@1.10.10-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-scaffolder-backend@1.23.1-next.1 + - @backstage/plugin-auth-backend@0.22.10-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.1 + - @backstage/backend-defaults@0.4.2-next.1 + - @backstage/plugin-app-backend@0.3.72-next.1 + - @backstage/plugin-devtools-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.5.4-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.1 + - @backstage/plugin-kubernetes-backend@0.18.4-next.1 + - @backstage/plugin-permission-backend@0.5.47-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.1 + - @backstage/plugin-search-backend@1.5.15-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.1 + - @backstage/plugin-search-backend-node@1.2.28-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.1 + - @backstage/plugin-notifications-backend@0.3.4-next.1 + - @backstage/plugin-signals-backend@0.1.9-next.1 + +## 0.0.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-notifications-backend@0.3.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + +## 0.0.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-notifications-backend@0.3.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.8 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5 + - @backstage/plugin-catalog-backend-module-openapi@0.1.40 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/catalog-model@1.5.0 + ## 0.0.28-next.2 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 459db3c317..cafe89a527 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.28-next.2", + "version": "0.0.29-next.2", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 1174b7bf6d..952f3315c4 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -15,9 +15,21 @@ */ import { createBackend } from '@backstage/backend-defaults'; +import { createBackendFeatureLoader } from '@backstage/backend-plugin-api'; const backend = createBackend(); +// An example of how to group together and load multiple features. You can also +// access root-scoped services by adding `deps`. +const searchLoader = createBackendFeatureLoader({ + *loader() { + yield import('@backstage/plugin-search-backend/alpha'); + yield import('@backstage/plugin-search-backend-module-catalog/alpha'); + yield import('@backstage/plugin-search-backend-module-explore/alpha'); + yield import('@backstage/plugin-search-backend-module-techdocs/alpha'); + }, +}); + backend.add(import('@backstage/plugin-auth-backend')); backend.add(import('./authModuleGithubProvider')); backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); @@ -36,13 +48,10 @@ backend.add(import('@backstage/plugin-permission-backend/alpha')); backend.add(import('@backstage/plugin-proxy-backend/alpha')); backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); backend.add(import('@backstage/plugin-scaffolder-backend-module-github')); -backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha')); -backend.add(import('@backstage/plugin-search-backend-module-explore/alpha')); -backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha')); backend.add( import('@backstage/plugin-catalog-backend-module-backstage-openapi'), ); -backend.add(import('@backstage/plugin-search-backend/alpha')); +backend.add(searchLoader); backend.add(import('@backstage/plugin-techdocs-backend/alpha')); backend.add(import('@backstage/plugin-signals-backend')); backend.add(import('@backstage/plugin-notifications-backend')); diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index dcf9073277..21995e4812 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/cli-node +## 0.2.7 + +### Patch Changes + +- 133464c: Added internal metadata for the new experimental `frontend-dynamic-container` role. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.6 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 56cf50a096..c727918510 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-node", - "version": "0.2.6", + "version": "0.2.7", "description": "Node.js library for Backstage CLIs", "backstage": { "role": "node-library" diff --git a/packages/cli-node/src/roles/PackageRoles.ts b/packages/cli-node/src/roles/PackageRoles.ts index 401568ad6d..70b62e2479 100644 --- a/packages/cli-node/src/roles/PackageRoles.ts +++ b/packages/cli-node/src/roles/PackageRoles.ts @@ -58,6 +58,11 @@ const packageRoleInfos: PackageRoleInfo[] = [ platform: 'web', output: ['types', 'esm'], }, + { + role: 'frontend-dynamic-container' as PackageRole, // experimental + platform: 'web', + output: ['bundle'], + }, { role: 'backend-plugin', platform: 'node', diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index a2fae6e3c0..887445aac7 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,120 @@ # @backstage/cli +## 0.27.0-next.3 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/config-loader@1.9.0-next.2 + - @backstage/cli-node@0.2.7 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.27.0-next.2 + +### Patch Changes + +- b2d97fd: Fixing loading of additional config files with new `ConfigSources` +- adabb40: New command now supports setting package license +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.9.0-next.1 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.14.0-next.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.27.0-next.1 + +### Patch Changes + +- e6e7d86: Switched the target from `'ES2022'` to `'es2022'` for better compatibility with older versions of `swc`. +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.27.0-next.0 + +### Minor Changes + +- 32a38e1: **BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands. + + The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files. + + The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic. + + The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches. + + The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future. + +### Patch Changes + +- 7eb08a6: Add frontend-dynamic-container role to eslint config factory +- fbc7819: Use ES2022 in CLI bundler +- e53074f: Updated default backend plugin to use `RootConfigService` instead of `Config`. This also removes the dependency on `@backstage/config` as it's no longer used. +- ee2b0e5: The experimental module federation build now has the ability to force the use of development versions of `react` and `react-dom` by setting the `FORCE_REACT_DEVELOPMENT` flag. +- 239dffc: Remove usage of deprecated functionality from @backstage/config-loader +- 0eedec3: Add support for dynamic plugins via the EXPERIMENTAL_MODULE_FEDERATION environment variable when running `yarn start`. +- dc4fb4f: Fix for `repo build --all` not properly detecting the experimental public entry point. +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.26.11 + +### Patch Changes + +- 133464c: Added experimental support for dynamic frontend plugin builds, enabled via setting `EXPERIMENTAL_MODULE_FEDERATION` for the app build, and using the `frontend-dynamic-container` package role to create a container. Both of these are experimental and will change in the future. +- e2e320c: - remove unused dependencies `winston` and `yn` from the template of backend plugins; + - update `msw` to version `2.3.1` in the template of backend plugins; + starting with v1 and switching later to v2 is tedious and not straight forward; it's easier to start with v2; +- 0540c5a: Updated the scaffolding output message for `plugin-common` in `backstage-cli`. Now, when executing `backstage-cli new` to create a new `plugin-common` package, the output message accurately reflects the action by displaying `Creating common plugin package...` instead of the previous, less accurate `Creating backend plugin...`. +- 7652db4: Only bootstrap global-agent if it's actually being used +- f0c0039: Fix issue with CLI that was preventing upgrading from 1.28 +- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware +- da90cce: Updated dependency `esbuild` to `^0.21.0`. +- a60d73b: Fix a few minor issues with the backend template that were causing failing linting checks in the main repo. +- 0510d98: Subpath export `package.json` should be of a unique name to avoid typescript resolution issues +- 4baac0c: The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. +- Updated dependencies + - @backstage/cli-node@0.2.7 + - @backstage/integration@1.13.0 + - @backstage/config-loader@1.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + ## 0.26.11-next.1 ### Patch Changes diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 01b0f7ddec..980d305c12 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -22,7 +22,6 @@ Commands: package [command] migrate [command] versions:bump [options] - versions:check [options] versions:migrate [options] clean build-workspace [options] [packages...] @@ -194,6 +193,7 @@ Options: --scope --npm-registry --baseVersion + --license --no-private -h, --help ``` @@ -607,16 +607,6 @@ Options: -h, --help ``` -### `backstage-cli versions:check` - -``` -Usage: backstage-cli versions:check [options] - -Options: - --fix - -h, --help -``` - ### `backstage-cli versions:migrate` ``` diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index 6bc200cade..96d8478ec0 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -201,6 +201,7 @@ function createConfigForRole(dir, role, extraConfig = {}) { case 'frontend': case 'frontend-plugin': case 'frontend-plugin-module': + case 'frontend-dynamic-container': return createConfig(dir, { ...extraConfig, extends: [ diff --git a/packages/cli/package.json b/packages/cli/package.json index 393f1217e1..ba45b8f514 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.26.11-next.1", + "version": "0.27.0-next.3", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" @@ -53,6 +53,7 @@ "@backstage/release-manifests": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", + "@module-federation/enhanced": "^0.1.19", "@octokit/graphql": "^5.0.0", "@octokit/graphql-schema": "^13.7.0", "@octokit/oauth-app": "^4.2.0", @@ -120,7 +121,7 @@ "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.4.2", "minimatch": "^9.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "node-libs-browser": "^2.2.1", "npm-packlist": "^5.0.0", "ora": "^5.3.0", diff --git a/packages/cli/src/commands/build/buildFrontend.ts b/packages/cli/src/commands/build/buildFrontend.ts index 6d7ca2e6a9..f29e0bdd38 100644 --- a/packages/cli/src/commands/build/buildFrontend.ts +++ b/packages/cli/src/commands/build/buildFrontend.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'path'; -import { buildBundle } from '../../lib/bundler'; +import { buildBundle, getModuleFederationOptions } from '../../lib/bundler'; import { getEnvironmentParallelism } from '../../lib/parallel'; import { loadCliConfig } from '../../lib/config'; @@ -24,16 +24,22 @@ interface BuildAppOptions { targetDir: string; writeStats: boolean; configPaths: string[]; + isModuleFederationRemote?: true; } export async function buildFrontend(options: BuildAppOptions) { const { targetDir, writeStats, configPaths } = options; const { name } = await fs.readJson(resolvePath(targetDir, 'package.json')); + await buildBundle({ targetDir, entry: 'src/index', parallelism: getEnvironmentParallelism(), statsJsonEnabled: writeStats, + moduleFederation: getModuleFederationOptions( + name, + options.isModuleFederationRemote, + ), ...(await loadCliConfig({ args: configPaths, fromPackage: name, diff --git a/packages/cli/src/commands/build/command.ts b/packages/cli/src/commands/build/command.ts index f15ae27ee0..c0ad3c912b 100644 --- a/packages/cli/src/commands/build/command.ts +++ b/packages/cli/src/commands/build/command.ts @@ -22,6 +22,7 @@ import { paths } from '../../lib/paths'; import { buildFrontend } from './buildFrontend'; import { buildBackend } from './buildBackend'; import { isValidUrl } from '../../lib/urls'; +import chalk from 'chalk'; export async function command(opts: OptionValues): Promise { const role = await findRoleFromCommand(opts); @@ -49,6 +50,21 @@ export async function command(opts: OptionValues): Promise { }); } + // experimental + if ((role as string) === 'frontend-dynamic-container') { + console.log( + chalk.yellow( + `⚠️ WARNING: The 'frontend-dynamic-container' package role is experimental and will receive immediate breaking changes in the future.`, + ), + ); + return buildFrontend({ + targetDir: paths.targetDir, + configPaths: [], + writeStats: Boolean(opts.stats), + isModuleFederationRemote: true, + }); + } + const roleInfo = PackageRoles.getRoleInfo(role); const outputs = new Set(); diff --git a/packages/cli/src/commands/create-plugin/createPlugin.ts b/packages/cli/src/commands/create-plugin/createPlugin.ts index 7fcb0aef1a..f8d7e54e97 100644 --- a/packages/cli/src/commands/create-plugin/createPlugin.ts +++ b/packages/cli/src/commands/create-plugin/createPlugin.ts @@ -19,16 +19,16 @@ import { promisify } from 'util'; import chalk from 'chalk'; import inquirer, { Answers, Question } from 'inquirer'; import { exec as execCb } from 'child_process'; -import { resolve as resolvePath, join as joinPath } from 'path'; +import { join as joinPath, resolve as resolvePath } from 'path'; import camelCase from 'lodash/camelCase'; import upperFirst from 'lodash/upperFirst'; import os from 'os'; import { OptionValues } from 'commander'; import { assertError } from '@backstage/errors'; import { - parseOwnerIds, addCodeownersEntry, getCodeownersFilePath, + parseOwnerIds, } from '../../lib/codeowners'; import { paths } from '../../lib/paths'; import { Task, templatingTask } from '../../lib/tasks'; @@ -266,6 +266,7 @@ export default async (opts: OptionValues) => { const { version: pluginVersion } = isMonoRepo ? await fs.readJson(paths.resolveTargetRoot('lerna.json')) : { version: '0.1.0' }; + const license = opts.license ?? 'Apache-2.0'; let lockfile: Lockfile | undefined; try { @@ -299,6 +300,7 @@ export default async (opts: OptionValues) => { name, privatePackage, npmRegistry, + license, }, createPackageVersionProvider(lockfile), isMonoRepo, diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 25a3a4e26c..7c3192fb2e 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -254,6 +254,10 @@ export function registerCommands(program: Command) { '--baseVersion ', 'The version to use for any new packages (default: 0.1.0)', ) + .option( + '--license ', + 'The license to use for any new packages (default: Apache-2.0)', + ) .option('--no-private', 'Do not mark new packages as private') .action(lazy(() => import('./new/new').then(m => m.default))); @@ -396,7 +400,7 @@ export function registerCommands(program: Command) { .action(lazy(() => import('./versions/bump').then(m => m.default))); program - .command('versions:check') + .command('versions:check', { hidden: true }) .option('--fix', 'Fix any auto-fixable versioning problems') .description('Check Backstage package versioning') .action(lazy(() => import('./versions/lint').then(m => m.default))); diff --git a/packages/cli/src/commands/new/new.ts b/packages/cli/src/commands/new/new.ts index 61e27af3c5..2733b0be9b 100644 --- a/packages/cli/src/commands/new/new.ts +++ b/packages/cli/src/commands/new/new.ts @@ -70,11 +70,14 @@ export default async (opts: OptionValues) => { return dir; } + const license = opts.license ?? 'Apache-2.0'; + let modified = false; try { await factory.create(options, { isMonoRepo: await isMonoRepo(), defaultVersion, + license, scope: opts.scope?.replace(/^@/, ''), npmRegistry: opts.npmRegistry, private: Boolean(opts.private), diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index 2f2af95d85..aa46b717bb 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -15,6 +15,7 @@ */ import { OptionValues } from 'commander'; +import { PackageRole } from '@backstage/cli-node'; import { findRoleFromCommand } from '../../lib/role'; import { startBackend, startBackendPlugin } from './startBackend'; import { startFrontend } from './startFrontend'; @@ -47,6 +48,13 @@ export async function command(opts: OptionValues): Promise { case 'frontend-plugin': case 'frontend-plugin-module': return startFrontend({ entry: 'dev/index', ...options }); + case 'frontend-dynamic-container' as PackageRole: // experimental + return startFrontend({ + entry: 'src/index', + ...options, + skipOpenBrowser: true, + isModuleFederationRemote: true, + }); default: throw new Error( `Start command is not supported for package role '${role}'`, diff --git a/packages/cli/src/commands/start/startFrontend.ts b/packages/cli/src/commands/start/startFrontend.ts index a809473788..20faf4a9ff 100644 --- a/packages/cli/src/commands/start/startFrontend.ts +++ b/packages/cli/src/commands/start/startFrontend.ts @@ -14,7 +14,9 @@ * limitations under the License. */ -import { serveBundle } from '../../lib/bundler'; +import { readJson } from 'fs-extra'; +import { getModuleFederationOptions, serveBundle } from '../../lib/bundler'; +import { paths } from '../../lib/paths'; interface StartAppOptions { verifyVersions?: boolean; @@ -22,14 +24,23 @@ interface StartAppOptions { checksEnabled: boolean; configPaths: string[]; + skipOpenBrowser?: boolean; + isModuleFederationRemote?: boolean; } export async function startFrontend(options: StartAppOptions) { + const { name } = await readJson(paths.resolveTarget('package.json')); + const waitForExit = await serveBundle({ entry: options.entry, checksEnabled: options.checksEnabled, configPaths: options.configPaths, verifyVersions: options.verifyVersions, + skipOpenBrowser: options.skipOpenBrowser, + moduleFederation: getModuleFederationOptions( + name, + options.isModuleFederationRemote, + ), }); await waitForExit(); diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index 0dfe2f61c3..cc48b91fd8 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -18,15 +18,11 @@ import fs from 'fs-extra'; import { Command } from 'commander'; import * as runObj from '../../lib/run'; import bump, { bumpBackstageJsonVersion, createVersionFinder } from './bump'; -import { - setupRequestMockHandlers, - withLogCollector, -} from '@backstage/test-utils'; +import { registerMswTestHooks, withLogCollector } from '@backstage/test-utils'; import { YarnInfoInspectData } from '../../lib/versioning/packages'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { NotFoundError } from '@backstage/errors'; -import { Lockfile } from '../../lib/versioning/Lockfile'; import { MockDirectory, createMockDirectory, @@ -120,17 +116,6 @@ const lockfileMock = `${HEADER} version "1.0.3" `; -// This is the lockfile that we produce to unlock versions before we run yarn install -const lockfileMockResult = `${HEADER} -"@backstage/core@^1.0.5": - version "1.0.6" - dependencies: - "@backstage/core-api" "^1.0.6" - -"@backstage/theme@^1.0.0": - version "1.0.0" -`; - // Avoid flakes by comparing sorted log lines. File system access is async, which leads to the log line order being indeterministic const expectLogsToMatch = ( recievedLogs: String[], @@ -156,7 +141,7 @@ describe('bump', () => { }); const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); it('should bump backstage dependencies', async () => { mockDir.setContent({ @@ -207,11 +192,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/core in a to ^1.0.6', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/theme in b to ^2.0.0', @@ -223,9 +204,8 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(3); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); - expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core-api'); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme'); expect(runObj.run).toHaveBeenCalledTimes(1); @@ -235,12 +215,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -315,11 +289,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/core in a to ^1.0.6', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/theme in b to ^2.0.0', @@ -331,9 +301,8 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(3); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); - expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core-api'); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme'); expect(runObj.run).not.toHaveBeenCalledWith( @@ -342,12 +311,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -428,12 +391,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/theme in b to ^5.0.0', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/core in a to ^1.0.6', @@ -446,9 +404,8 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(1); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); - expect(mockFetchPackageInfo).not.toHaveBeenCalledWith('@backstage/theme'); expect(runObj.run).toHaveBeenCalledTimes(1); expect(runObj.run).toHaveBeenCalledWith( @@ -457,12 +414,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -632,12 +583,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/theme in b to ^5.0.0', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/core in a to ^1.0.6', @@ -661,21 +607,6 @@ describe('bump', () => { "@backstage-extra/custom-two@^1.0.0": version "1.0.0" -`; - const customLockfileMockResult = `${HEADER} -"@backstage-extra/custom-two@^1.0.0": - version "1.0.0" - -"@backstage-extra/custom@^1.1.0": - version "1.1.0" - -"@backstage/core@^1.0.5": - version "1.0.6" - dependencies: - "@backstage/core-api" "^1.0.6" - -"@backstage/theme@^1.0.0": - version "1.0.0" `; mockDir.setContent({ 'yarn.lock': customLockfileMock, @@ -734,12 +665,7 @@ describe('bump', () => { 'Checking for updates of @backstage-extra/custom', 'Checking for updates of @backstage-extra/custom-two', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage-extra/custom@^1.0.1 ~> 1.1.0', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/core in a to ^1.0.6', 'bumping @backstage-extra/custom in a to ^1.1.0', 'bumping @backstage-extra/custom-two in a to ^2.0.0', @@ -757,7 +683,7 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(5); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(4); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme'); @@ -768,12 +694,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toEqual(customLockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -801,7 +721,7 @@ describe('bump', () => { it('should ignore not found packages', async () => { mockDir.setContent({ - 'yarn.lock': lockfileMockResult, + 'yarn.lock': lockfileMock, 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], @@ -851,21 +771,11 @@ describe('bump', () => { 'Checking for updates of @backstage/theme', 'Package info not found, ignoring package @backstage/core', 'Package info not found, ignoring package @backstage/theme', - 'Checking for updates of @backstage/core', - 'Checking for updates of @backstage/theme', - 'Package info not found, ignoring package @backstage/core', - 'Package info not found, ignoring package @backstage/theme', 'All Backstage packages are up to date!', ]); expect(runObj.run).toHaveBeenCalledTimes(0); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -886,83 +796,6 @@ describe('bump', () => { }, }); }); - - // eslint-disable-next-line jest/expect-expect - it('should log duplicates', async () => { - jest.spyOn(Lockfile.prototype, 'analyze').mockReturnValue({ - invalidRanges: [], - newVersions: [], - newRanges: [ - { - name: '@backstage/backend-app-api', - oldRange: '^1.0.0', - newRange: '^2.0.0', - oldVersion: '1.0.0', - newVersion: '2.0.0', - }, - ], - }); - mockDir.setContent({ - 'yarn.lock': `${HEADER} -"@backstage/backend-app-api@^1.0.0": - version "1.0.0" -`, - 'package.json': JSON.stringify({ - workspaces: { - packages: ['packages/*'], - }, - }), - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/backend-app-api': '^1.0.0', - }, - }), - }, - }, - }); - - jest.spyOn(runObj, 'run').mockResolvedValue(undefined); - worker.use( - rest.get( - 'https://versions.backstage.io/v1/tags/main/manifest.json', - (_, res, ctx) => - res( - ctx.status(200), - ctx.json({ - packages: [ - { - name: '@backstage/backend-app-api', - version: '2.0.0', - }, - ], - }), - ), - ), - ); - const { log: logs } = await withLogCollector(['log', 'warn'], async () => { - await bump({ pattern: null, release: 'main' } as unknown as Command); - }); - expectLogsToMatch(logs, [ - 'Using default pattern glob @backstage/*', - 'Checking for updates of @backstage/backend-app-api', - 'Checking for updates of @backstage/backend-app-api', - 'Some packages are outdated, updating', - 'bumping @backstage/backend-app-api in a to ^2.0.0', - 'Running yarn install to install new versions', - 'Checking for moved packages to the @backstage-community namespace...', - '⚠️ The following packages may have breaking changes:', - ' @backstage/backend-app-api : 1.0.0 ~> 2.0.0', - ' https://github.com/backstage/backstage/blob/master/packages/backend-app-api/CHANGELOG.md', - 'Version bump complete!', - ' ⚠️ Warning! ⚠️', - ' The below package(s) have incompatible duplicate installations, likely due to a bad dependency in a plugin.', - ' You can investigate this by running `yarn why `, and report the issue to the plugin maintainers.', - ' @backstage/backend-app-api', - ]); - }); }); describe('bumpBackstageJsonVersion', () => { diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index d6d5f424ba..5b981d3890 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -24,7 +24,6 @@ import fs from 'fs-extra'; import chalk from 'chalk'; import ora from 'ora'; import semver from 'semver'; -import { minimatch } from 'minimatch'; import { OptionValues } from 'commander'; import { isError, NotFoundError } from '@backstage/errors'; import { resolve as resolvePath } from 'path'; @@ -36,7 +35,6 @@ import { Lockfile, YarnInfoInspectData, } from '../../lib/versioning'; -import { forbiddenDuplicatesFilter } from './lint'; import { BACKSTAGE_JSON } from '@backstage/cli-common'; import { runParallelWorkers } from '../../lib/parallel'; import { @@ -44,7 +42,6 @@ import { getManifestByVersion, ReleaseManifest, } from '@backstage/release-manifests'; -import { PackageGraph } from '@backstage/cli-node'; import { migrateMovedPackages } from './migrate'; function shouldUseGlobalAgent(): boolean { @@ -125,8 +122,6 @@ export default async (opts: OptionValues) => { // Next check with the package registry to see which dependency ranges we need to bump const versionBumps = new Map(); - // Track package versions that we want to remove from yarn.lock in order to trigger a bump - const unlocked = Array<{ name: string; range: string; target: string }>(); await runParallelWorkers({ parallelismFactor: 4, @@ -157,72 +152,13 @@ export default async (opts: OptionValues) => { }, }); - const filter = (name: string) => minimatch(name, pattern); - - // Check for updates of transitive backstage dependencies - await runParallelWorkers({ - parallelismFactor: 4, - items: lockfile.keys(), - async worker(name) { - // Only check @backstage packages and friends, we don't want this to do a full update of all deps - if (!filter(name)) { - return; - } - - let target: string; - try { - target = await findTargetVersion(name); - } catch (error) { - if (isError(error) && error.name === 'NotFoundError') { - console.log(`Package info not found, ignoring package ${name}`); - return; - } - throw error; - } - - for (const entry of lockfile.get(name) ?? []) { - // Ignore lockfile entries that don't satisfy the version range, since - // these can't cause the package to be locked to an older version - if (!semver.satisfies(target, entry.range)) { - continue; - } - // Unlock all entries that are within range but on the old version - unlocked.push({ name, range: entry.range, target }); - } - }, - }); - - console.log(); - // Write all discovered version bumps to package.json in this repo - if (versionBumps.size === 0 && unlocked.length === 0) { + if (versionBumps.size === 0) { console.log(chalk.green('All Backstage packages are up to date!')); } else { console.log(chalk.yellow('Some packages are outdated, updating')); console.log(); - if (unlocked.length > 0) { - const removed = new Set(); - for (const { name, range, target } of unlocked) { - // Don't bother removing lockfile entries if they're already on the correct version - const existingEntry = lockfile.get(name)?.find(e => e.range === range); - if (existingEntry?.version === target) { - continue; - } - const key = JSON.stringify({ name, range }); - if (!removed.has(key)) { - removed.add(key); - console.log( - `${chalk.magenta('unlocking')} ${name}@${chalk.yellow( - range, - )} ~> ${chalk.yellow(target)}`, - ); - lockfile.remove(name, range); - } - } - await lockfile.save(lockfilePath); - } - const breakingUpdates = new Map(); await runParallelWorkers({ parallelismFactor: 4, @@ -334,38 +270,6 @@ export default async (opts: OptionValues) => { } console.log(); - - // Finally we make sure the new lockfile doesn't have any duplicates - const dedupLockfile = await Lockfile.load(lockfilePath); - - const result = dedupLockfile.analyze({ - filter, - localPackages: PackageGraph.fromPackages( - await PackageGraph.listTargetPackages(), - ), - }); - - const forbiddenNewRanges = result.newRanges.filter(({ name }) => - forbiddenDuplicatesFilter(name), - ); - if (forbiddenNewRanges.length > 0) { - console.log(chalk.yellow(' ⚠️ Warning! ⚠️')); - console.log(); - console.log( - chalk.yellow( - ' The below package(s) have incompatible duplicate installations, likely due to a bad dependency in a plugin.', - ), - ); - console.log( - chalk.yellow( - ' You can investigate this by running `yarn why `, and report the issue to the plugin maintainers.', - ), - ); - console.log(); - for (const { name } of forbiddenNewRanges) { - console.log(chalk.yellow(` ${name}`)); - } - } }; export function createStrictVersionFinder(options: { diff --git a/packages/cli/src/commands/versions/lint.ts b/packages/cli/src/commands/versions/lint.ts index bfb2a752a0..66b5fc04c4 100644 --- a/packages/cli/src/commands/versions/lint.ts +++ b/packages/cli/src/commands/versions/lint.ts @@ -14,116 +14,8 @@ * limitations under the License. */ -import { OptionValues } from 'commander'; -import { Lockfile } from '../../lib/versioning'; -import { paths } from '../../lib/paths'; -import partition from 'lodash/partition'; -import { PackageGraph } from '@backstage/cli-node'; - -// Packages that we try to avoid duplicates for -const INCLUDED = [/^@backstage\//]; - -export const includedFilter = (name: string) => - INCLUDED.some(pattern => pattern.test(name)); - -// Packages that are not allowed to have any duplicates -const FORBID_DUPLICATES = [/^@backstage\/\w+-app-api$/, /^@backstage\/plugin-/]; - -// There are some packages that ARE explicitly allowed to have duplicates since -// they handle that appropriately. This takes precedence over FORBID_DUPLICATES -// above. -const ALLOW_DUPLICATES = [ - /^@backstage\/core-plugin-api$/, - // Duplicates of libraries are OK - // TODO(Rugvip): Check this using package role instead - /^@backstage\/plugin-.*-react$/, - /^@backstage\/plugin-.*-node$/, - /^@backstage\/plugin-.*-common$/, -]; - -export const forbiddenDuplicatesFilter = (name: string) => - FORBID_DUPLICATES.some(pattern => pattern.test(name)) && - !ALLOW_DUPLICATES.some(pattern => pattern.test(name)); - -export default async (cmd: OptionValues) => { - const fix = Boolean(cmd.fix); - - let success = true; - - const lockfilePath = paths.resolveTargetRoot('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ - filter: includedFilter, - localPackages: PackageGraph.fromPackages( - await PackageGraph.listTargetPackages(), - ), - }); - - logArray( - result.invalidRanges, - "The following packages versions are invalid and can't be analyzed:", - e => ` ${e.name} @ ${e.range}`, +export default async () => { + throw new Error( + 'This command has been removed, please consider alternatives such as `yarn dedupe` instead.', ); - - if (fix) { - lockfile.replaceVersions(result.newVersions); - await lockfile.save(lockfilePath); - } else { - const [newVersionsForbidden, newVersionsAllowed] = partition( - result.newVersions, - ({ name }) => forbiddenDuplicatesFilter(name), - ); - if (newVersionsForbidden.length && !fix) { - success = false; - } - - logArray( - newVersionsForbidden, - 'The following packages must be deduplicated, this can be done automatically with --fix', - e => - ` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`, - ); - logArray( - newVersionsAllowed, - 'The following packages can be deduplicated, this can be done automatically with --fix', - e => - ` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`, - ); - } - - const [newRangesForbidden, newRangesAllowed] = partition( - result.newRanges, - ({ name }) => forbiddenDuplicatesFilter(name), - ); - if (newRangesForbidden.length) { - success = false; - } - - logArray( - newRangesForbidden, - 'The following packages must be deduplicated by updating dependencies in package.json', - e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`, - ); - logArray( - newRangesAllowed, - 'The following packages can be deduplicated by updating dependencies in package.json', - e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`, - ); - - if (!success) { - throw new Error('Failed versioning check'); - } }; - -function logArray(arr: T[], header: string, each: (item: T) => string) { - if (arr.length === 0) { - return; - } - - console.log(header); - console.log(); - for (const e of arr) { - console.log(each(e)); - } - console.log(); -} diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index 232657a3f2..0aa91a90a6 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -42,41 +42,50 @@ export async function buildBundle(options: BuildOptions) { const paths = resolveBundlingPaths(options); const publicPaths = await resolveOptionalBundlingPaths({ + targetDir: options.targetDir, entry: 'src/index-public-experimental', dist: 'dist/public', }); - const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ - config: options.fullConfig, - targetPath: paths.targetPath, - }); - const commonConfigOptions = { ...options, checksEnabled: false, isDev: false, getFrontendAppConfigs: () => options.frontendAppConfigs, }; - const configs = [ - await createConfig(paths, { - ...commonConfigOptions, - additionalEntryPoints: detectedModulesEntryPoint, - appMode: publicPaths ? 'protected' : 'public', - }), - ]; - if (publicPaths) { - console.log( - chalk.yellow( - `⚠️ WARNING: The app /public entry point is an experimental feature that may receive immediate breaking changes.`, - ), - ); + const configs = []; + + if (options.moduleFederation?.mode === 'remote') { + // Package detection is disabled for remote bundles + configs.push(await createConfig(paths, commonConfigOptions)); + } else { + const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ + config: options.fullConfig, + targetPath: paths.targetPath, + }); + configs.push( - await createConfig(publicPaths, { + await createConfig(paths, { ...commonConfigOptions, - appMode: 'public', + additionalEntryPoints: detectedModulesEntryPoint, + appMode: publicPaths ? 'protected' : 'public', }), ); + + if (publicPaths) { + console.log( + chalk.yellow( + `⚠️ WARNING: The app /public entry point is an experimental feature that may receive immediate breaking changes.`, + ), + ); + configs.push( + await createConfig(publicPaths, { + ...commonConfigOptions, + appMode: 'public', + }), + ); + } } const isCi = yn(process.env.CI, { default: false }); diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 53db7f3597..42cdae24e3 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -14,8 +14,13 @@ * limitations under the License. */ -import { BackendBundlingOptions, BundlingOptions } from './types'; -import { posix as posixPath, resolve as resolvePath } from 'path'; +import { + BackendBundlingOptions, + BundlingOptions, + ModuleFederationOptions, +} from './types'; +import { posix as posixPath, resolve as resolvePath, dirname } from 'path'; +import chalk from 'chalk'; import webpack, { ProvidePlugin } from 'webpack'; import { BackstagePackage } from '@backstage/cli-node'; @@ -24,15 +29,17 @@ import { Config } from '@backstage/config'; import ESLintPlugin from 'eslint-webpack-plugin'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; +import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack'; import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; +import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin'; import { paths as cliPaths } from '../../lib/paths'; import fs from 'fs-extra'; import { getPackages } from '@manypkg/get-packages'; import { isChildPath } from '@backstage/cli-common'; import nodeExternals from 'webpack-node-externals'; -import { optimization } from './optimization'; +import { optimization as optimizationConfig } from './optimization'; import pickBy from 'lodash/pickBy'; import { readEntryPoints } from '../entryPoints'; import { runPlain } from '../run'; @@ -43,15 +50,42 @@ import { hasReactDomClient } from './hasReactDomClient'; const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE'; -export function resolveBaseUrl(config: Config): URL { +export function resolveBaseUrl( + config: Config, + moduleFederation?: ModuleFederationOptions, +): URL { const baseUrl = config.getOptionalString('app.baseUrl'); + + const defaultBaseUrl = + moduleFederation?.mode === 'remote' + ? `http://localhost:${process.env.PORT ?? '3000'}` + : 'http://localhost:3000'; + try { - return new URL(baseUrl ?? '/', 'http://localhost:3000'); + return new URL(baseUrl ?? '/', defaultBaseUrl); } catch (error) { throw new Error(`Invalid app.baseUrl, ${error}`); } } +export function resolveEndpoint( + config: Config, + moduleFederation?: ModuleFederationOptions, +): { + host: string; + port: number; +} { + const url = resolveBaseUrl(config, moduleFederation); + + return { + host: config.getOptionalString('app.listen.host') ?? url.hostname, + port: + config.getOptionalNumber('app.listen.port') ?? + Number(url.port) ?? + (url.protocol === 'https:' ? 443 : 80), + }; +} + async function readBuildInfo() { const timestamp = Date.now(); @@ -92,7 +126,13 @@ export async function createConfig( paths: BundlingPaths, options: BundlingOptions, ): Promise { - const { checksEnabled, isDev, frontendConfig, publicSubPath = '' } = options; + const { + checksEnabled, + isDev, + frontendConfig, + moduleFederation, + publicSubPath = '', + } = options; const { plugins, loaders } = transforms(options); // Any package that is part of the monorepo but outside the monorepo root dir need @@ -100,12 +140,29 @@ export async function createConfig( const { packages } = await getPackages(cliPaths.targetDir); const externalPkgs = packages.filter(p => !isChildPath(paths.root, p.dir)); - const validBaseUrl = resolveBaseUrl(frontendConfig); + const validBaseUrl = resolveBaseUrl(frontendConfig, moduleFederation); let publicPath = validBaseUrl.pathname.replace(/\/$/, ''); if (publicSubPath) { publicPath = `${publicPath}${publicSubPath}`.replace('//', '/'); } + if (isDev) { + const { host, port } = resolveEndpoint( + options.frontendConfig, + options.moduleFederation, + ); + + plugins.push( + new ReactRefreshPlugin({ + overlay: { + sockProtocol: 'ws', + sockHost: host, + sockPort: port, + }, + }), + ); + } + if (checksEnabled) { plugins.push( new ForkTsCheckerWebpackPlugin({ @@ -128,18 +185,83 @@ export async function createConfig( }), ); - plugins.push( - new HtmlWebpackPlugin({ - meta: { - 'backstage-app-mode': options?.appMode ?? 'public', - }, - template: paths.targetHtml, - templateParameters: { - publicPath, - config: frontendConfig, - }, - }), - ); + if (options.moduleFederation?.mode !== 'remote') { + plugins.push( + new HtmlWebpackPlugin({ + meta: { + 'backstage-app-mode': options?.appMode ?? 'public', + }, + template: paths.targetHtml, + templateParameters: { + publicPath, + config: frontendConfig, + }, + }), + ); + } + + if (options.moduleFederation) { + const isRemote = options.moduleFederation?.mode === 'remote'; + + plugins.push( + new ModuleFederationPlugin({ + ...(isRemote && { + filename: 'remoteEntry.js', + exposes: { + '.': paths.targetEntry, + }, + }), + name: options.moduleFederation.name, + runtime: false, + shared: { + // React + react: { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + 'react-dom': { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + // React Router + 'react-router': { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + 'react-router-dom': { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + // MUI v4 + '@material-ui/core/styles': { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + '@material-ui/styles': { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + // MUI v5 + '@mui/material/styles/': { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + '@emotion/react': { + singleton: true, + requiredVersion: '*', + eager: !isRemote, + }, + }, + }), + ); + } const buildInfo = await readBuildInfo(); plugins.push( @@ -166,12 +288,53 @@ export async function createConfig( require.resolve('react-refresh'), ]; + const mode = isDev ? 'development' : 'production'; + const optimization = optimizationConfig(options); + + if ( + mode === 'production' && + process.env.EXPERIMENTAL_MODULE_FEDERATION && + process.env.FORCE_REACT_DEVELOPMENT + ) { + console.log( + chalk.yellow( + `⚠️ WARNING: Forcing react and react-dom into development mode. This build should not be used in production.`, + ), + ); + + const reactPackageDirs = [ + `${dirname(require.resolve('react/package.json'))}/`, + `${dirname(require.resolve('react-dom/package.json'))}/`, + ]; + + // Don't define process.env.NODE_ENV with value matching config.mode. If we + // don't set this to false, webpack will define the value of + // process.env.NODE_ENV for us, and the definition below will be ignored. + optimization.nodeEnv = false; + + // Instead, provide a custom definition which always uses "development" if + // the module is part of `react` or `react-dom`, and `config.mode` otherwise. + plugins.push( + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': webpack.DefinePlugin.runtimeValue( + ({ module }) => { + if (reactPackageDirs.some(val => module.resource.startsWith(val))) { + return '"development"'; + } + + return `"${mode}"`; + }, + ), + }), + ); + } + const withCache = yn(process.env[BUILD_CACHE_ENV_VAR], { default: false }); return { - mode: isDev ? 'development' : 'production', + mode, profile: false, - optimization: optimization(options), + optimization, bail: false, performance: { hints: false, // we check the gzip size instead @@ -211,8 +374,10 @@ export async function createConfig( rules: loaders, }, output: { + uniqueName: options.moduleFederation?.name, path: paths.targetDist, - publicPath: `${publicPath}/`, + publicPath: + options.moduleFederation?.mode === 'remote' ? 'auto' : `${publicPath}/`, filename: isDev ? '[name].js' : 'static/[name].[fullhash:8].js', chunkFilename: isDev ? '[name].chunk.js' diff --git a/packages/cli/src/lib/bundler/index.ts b/packages/cli/src/lib/bundler/index.ts index a3b584efc4..2219784dc9 100644 --- a/packages/cli/src/lib/bundler/index.ts +++ b/packages/cli/src/lib/bundler/index.ts @@ -16,4 +16,5 @@ export { serveBackend } from './backend'; export { buildBundle } from './bundle'; +export { getModuleFederationOptions } from './moduleFederation'; export { serveBundle } from './server'; diff --git a/packages/cli/src/lib/bundler/moduleFederation.ts b/packages/cli/src/lib/bundler/moduleFederation.ts new file mode 100644 index 0000000000..ae3f9ab048 --- /dev/null +++ b/packages/cli/src/lib/bundler/moduleFederation.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import { ModuleFederationOptions } from './types'; + +export function getModuleFederationOptions( + name: string, + isModuleFederationRemote?: boolean, +): ModuleFederationOptions | undefined { + if ( + !isModuleFederationRemote && + !process.env.EXPERIMENTAL_MODULE_FEDERATION + ) { + return undefined; + } + + console.log( + chalk.yellow( + `⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`, + ), + ); + + return { + mode: isModuleFederationRemote ? 'remote' : 'host', + // The default output mode requires the name to be a usable as a code + // symbol, there might be better options here but for now we need to + // sanitize the name. + name: name.replaceAll('@', '').replaceAll('/', '__').replaceAll('-', '_'), + }; +} diff --git a/packages/cli/src/lib/bundler/optimization.ts b/packages/cli/src/lib/bundler/optimization.ts index 88a0343099..cf240b4791 100644 --- a/packages/cli/src/lib/bundler/optimization.ts +++ b/packages/cli/src/lib/bundler/optimization.ts @@ -28,8 +28,15 @@ export const optimization = ( minimize: !isDev, minimizer: [ new EsbuildPlugin({ - target: 'es2019', + target: 'ES2022', format: 'iife', + exclude: 'remoteEntry.js', + }), + // Avoid iife wrapping of module federation remote entry as it breaks the variable assignment + new EsbuildPlugin({ + target: 'ES2022', + format: undefined, + include: 'remoteEntry.js', }), ], runtimeChunk: 'single', diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 1da15cd37e..259f3263eb 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -14,23 +14,16 @@ * limitations under the License. */ -import { PackageGraph } from '@backstage/cli-node'; import { AppConfig } from '@backstage/config'; import chalk from 'chalk'; import fs from 'fs-extra'; -import uniq from 'lodash/uniq'; import openBrowser from 'react-dev-utils/openBrowser'; import webpack from 'webpack'; import WebpackDevServer from 'webpack-dev-server'; -import { - forbiddenDuplicatesFilter, - includedFilter, -} from '../../commands/versions/lint'; import { paths as libPaths } from '../../lib/paths'; import { loadCliConfig } from '../config'; -import { Lockfile } from '../versioning'; -import { createConfig, resolveBaseUrl } from './config'; +import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; import { ServeOptions } from './types'; @@ -41,38 +34,6 @@ export async function serveBundle(options: ServeOptions) { const targetPkg = await fs.readJson(paths.targetPackageJson); if (options.verifyVersions) { - const lockfile = await Lockfile.load( - libPaths.resolveTargetRoot('yarn.lock'), - ); - const result = lockfile.analyze({ - filter: includedFilter, - localPackages: PackageGraph.fromPackages( - await PackageGraph.listTargetPackages(), - ), - }); - const problemPackages = [...result.newVersions, ...result.newRanges] - .map(({ name }) => name) - .filter(forbiddenDuplicatesFilter); - - if (problemPackages.length > 1) { - console.log( - chalk.yellow( - `⚠️ Some of the following packages may be outdated or have duplicate installations: - - ${uniq(problemPackages).join(', ')} - `, - ), - ); - console.log( - chalk.yellow( - `⚠️ This can be resolved using the following command: - - yarn backstage-cli versions:check --fix - `, - ), - ); - } - if ( targetPkg.dependencies?.['react-router']?.includes('beta') || targetPkg.dependencies?.['react-router-dom']?.includes('beta') @@ -130,14 +91,11 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be } const { frontendConfig, fullConfig } = cliConfig; - const url = resolveBaseUrl(frontendConfig); - - const host = - frontendConfig.getOptionalString('app.listen.host') || url.hostname; - const port = - frontendConfig.getOptionalNumber('app.listen.port') || - Number(url.port) || - (url.protocol === 'https:' ? 443 : 80); + const url = resolveBaseUrl(frontendConfig, options.moduleFederation); + const { host, port } = resolveEndpoint( + frontendConfig, + options.moduleFederation, + ); const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ config: fullConfig, @@ -162,6 +120,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be const config = await createConfig(paths, { ...commonConfigOptions, additionalEntryPoints: detectedModulesEntryPoint, + moduleFederation: options.moduleFederation, }); if (process.env.EXPERIMENTAL_VITE) { @@ -232,14 +191,17 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be directory: paths.targetPublic, } : undefined, - historyApiFallback: { - // Paths with dots should still use the history fallback. - // See https://github.com/facebookincubator/create-react-app/issues/387. - disableDotRule: true, + historyApiFallback: + options.moduleFederation?.mode === 'remote' + ? false + : { + // Paths with dots should still use the history fallback. + // See https://github.com/facebookincubator/create-react-app/issues/387. + disableDotRule: true, - // The index needs to be rewritten relative to the new public path, including subroutes. - index: `${config.output?.publicPath}index.html`, - }, + // The index needs to be rewritten relative to the new public path, including subroutes. + index: `${config.output?.publicPath}index.html`, + }, server: url.protocol === 'https:' ? { @@ -256,7 +218,13 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be // When the dev server is behind a proxy, the host and public hostname differ allowedHosts: [url.hostname], client: { - webSocketURL: 'auto://0.0.0.0:0/ws', + webSocketURL: { hostname: host, port }, + }, + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, OPTIONS', + 'Access-Control-Allow-Headers': + 'X-Requested-With, content-type, Authorization', }, }, compiler, @@ -278,7 +246,9 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be } }); - openBrowser(url.href); + if (!options.skipOpenBrowser) { + openBrowser(url.href); + } const waitForExit = async () => { for (const signal of ['SIGINT', 'SIGTERM'] as const) { diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index da1eec4e11..302b2fbe68 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -17,7 +17,6 @@ import { ModuleOptions, WebpackPluginInstance } from 'webpack'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import { svgrTemplate } from '../svgrTemplate'; -import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin'; type Transforms = { loaders: ModuleOptions['rules']; @@ -58,7 +57,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'typescript', @@ -86,7 +85,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'ecmascript', @@ -119,7 +118,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'ecmascript', @@ -193,15 +192,7 @@ export const transforms = (options: TransformOptions): Transforms => { const plugins = new Array(); - if (isDev) { - if (!isBackend) { - plugins.push( - new ReactRefreshPlugin({ - overlay: { sockProtocol: 'ws' }, - }), - ); - } - } else { + if (!isDev) { plugins.push( new MiniCssExtractPlugin({ filename: 'static/[name].[contenthash:8].css', diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 85a641465f..f8e228c5c4 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -18,6 +18,13 @@ import { AppConfig, Config } from '@backstage/config'; import { BundlingPathsOptions } from './paths'; import { ConfigSchema } from '@backstage/config-loader'; +export type ModuleFederationOptions = { + // Unique name for this module federation bundle + name: string; + // Whether this is a host or remote bundle + mode: 'host' | 'remote'; +}; + export type BundlingOptions = { checksEnabled: boolean; isDev: boolean; @@ -29,12 +36,15 @@ export type BundlingOptions = { publicSubPath?: string; // Mode that the app is running in, 'protected' or 'public', default is 'public' appMode?: string; + moduleFederation?: ModuleFederationOptions; }; export type ServeOptions = BundlingPathsOptions & { checksEnabled: boolean; configPaths: string[]; verifyVersions?: boolean; + skipOpenBrowser?: boolean; + moduleFederation?: ModuleFederationOptions; }; export type BuildOptions = BundlingPathsOptions & { @@ -46,6 +56,7 @@ export type BuildOptions = BundlingPathsOptions & { frontendConfig: Config; frontendAppConfigs: AppConfig[]; fullConfig: Config; + moduleFederation?: ModuleFederationOptions; }; export type BackendBundlingOptions = { diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index 0c657b640e..aab16a8670 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -14,14 +14,9 @@ * limitations under the License. */ -import { - ConfigTarget, - loadConfig, - loadConfigSchema, -} from '@backstage/config-loader'; +import { ConfigSources, loadConfigSchema } from '@backstage/config-loader'; import { AppConfig, ConfigReader } from '@backstage/config'; import { paths } from './paths'; -import { isValidUrl } from './urls'; import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; @@ -37,13 +32,6 @@ type Options = { }; export async function loadCliConfig(options: Options) { - const configTargets: ConfigTarget[] = []; - options.args.forEach(arg => { - if (!isValidUrl(arg)) { - configTargets.push({ path: paths.resolveTarget(arg) }); - } - }); - // Consider all packages in the monorepo when loading in config const { packages } = await getPackages(paths.targetDir); @@ -75,32 +63,62 @@ export async function loadCliConfig(options: Options) { noUndeclaredProperties: options.strict, }); - const { appConfigs } = await loadConfig({ - experimentalEnvFunc: options.mockEnv + const source = ConfigSources.default({ + allowMissingDefaultConfig: true, + substitutionFunc: options.mockEnv ? async name => process.env[name] || 'x' : undefined, - configRoot: paths.targetRoot, - configTargets: configTargets, - watch: options.watch && { - onChange(newAppConfigs) { - const newFrontendAppConfigs = schema.process(newAppConfigs, { - visibility: options.fullVisibility - ? ['frontend', 'backend', 'secret'] - : ['frontend'], - withFilteredKeys: options.withFilteredKeys, - withDeprecatedKeys: options.withDeprecatedKeys, - ignoreSchemaErrors: !options.strict, - }); - options.watch?.(newFrontendAppConfigs); - }, - }, + watch: Boolean(options.watch), + rootDir: paths.targetRoot, + argv: options.args.flatMap(t => ['--config', paths.resolveTarget(t)]), }); + const appConfigs = await new Promise((resolve, reject) => { + async function loadConfigReaderLoop() { + let loaded = false; + + try { + const abortController = new AbortController(); + for await (const { configs } of source.readConfigData({ + signal: abortController.signal, + })) { + if (loaded) { + const newFrontendAppConfigs = schema.process(configs, { + visibility: options.fullVisibility + ? ['frontend', 'backend', 'secret'] + : ['frontend'], + withFilteredKeys: options.withFilteredKeys, + withDeprecatedKeys: options.withDeprecatedKeys, + ignoreSchemaErrors: !options.strict, + }); + options.watch?.(newFrontendAppConfigs); + } else { + resolve(configs); + loaded = true; + + if (!options.watch) { + abortController.abort(); + } + } + } + } catch (error) { + if (loaded) { + console.error(`Failed to reload configuration, ${error}`); + } else { + reject(error); + } + } + } + loadConfigReaderLoop(); + }); + + const configurationLoadedMessage = appConfigs.length + ? `Loaded config from ${appConfigs.map(c => c.context).join(', ')}` + : `No configuration files found, running without config`; + // printing to stderr to not clobber stdout in case the cli command // outputs structured data (e.g. as config:schema does) - process.stderr.write( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}\n`, - ); + process.stderr.write(`${configurationLoadedMessage}\n`); try { const frontendAppConfigs = schema.process(appConfigs, { diff --git a/packages/cli/src/lib/new/factories/backendModule.test.ts b/packages/cli/src/lib/new/factories/backendModule.test.ts index 2d6a4c9c83..59b5403239 100644 --- a/packages/cli/src/lib/new/factories/backendModule.test.ts +++ b/packages/cli/src/lib/new/factories/backendModule.test.ts @@ -79,6 +79,7 @@ describe('backendModule factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); diff --git a/packages/cli/src/lib/new/factories/backendModule.ts b/packages/cli/src/lib/new/factories/backendModule.ts index 67860b812e..de759538b1 100644 --- a/packages/cli/src/lib/new/factories/backendModule.ts +++ b/packages/cli/src/lib/new/factories/backendModule.ts @@ -75,6 +75,7 @@ export const backendModule = createFactory({ packageVersion: ctx.defaultVersion, privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/backendPlugin.test.ts b/packages/cli/src/lib/new/factories/backendPlugin.test.ts index f6eeb8cf33..3b90e2b0dd 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.test.ts @@ -78,6 +78,7 @@ describe('backendPlugin factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index fc77896461..9129a66075 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -64,6 +64,7 @@ export const backendPlugin = createFactory({ pluginVersion: ctx.defaultVersion, privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/frontendPlugin.test.ts b/packages/cli/src/lib/new/factories/frontendPlugin.test.ts index cca79dea2a..55e569a15f 100644 --- a/packages/cli/src/lib/new/factories/frontendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/frontendPlugin.test.ts @@ -80,6 +80,7 @@ describe('frontendPlugin factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); @@ -174,6 +175,7 @@ const router = ( defaultVersion: '1.0.0', markAsModified: () => {}, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); await expect( diff --git a/packages/cli/src/lib/new/factories/frontendPlugin.ts b/packages/cli/src/lib/new/factories/frontendPlugin.ts index 1058c879c1..41907d9d3a 100644 --- a/packages/cli/src/lib/new/factories/frontendPlugin.ts +++ b/packages/cli/src/lib/new/factories/frontendPlugin.ts @@ -67,6 +67,7 @@ export const frontendPlugin = createFactory({ pluginVersion: ctx.defaultVersion, privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts b/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts index e3673d21ba..69999761e9 100644 --- a/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts +++ b/packages/cli/src/lib/new/factories/nodeLibraryPackage.test.ts @@ -64,6 +64,7 @@ describe('nodeLibraryPackage factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); @@ -134,6 +135,7 @@ describe('nodeLibraryPackage factory', () => { defaultVersion: '1.0.0', markAsModified: () => {}, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(Task.forCommand).toHaveBeenCalledTimes(2); diff --git a/packages/cli/src/lib/new/factories/nodeLibraryPackage.ts b/packages/cli/src/lib/new/factories/nodeLibraryPackage.ts index 687caa7cd5..3d9029a01d 100644 --- a/packages/cli/src/lib/new/factories/nodeLibraryPackage.ts +++ b/packages/cli/src/lib/new/factories/nodeLibraryPackage.ts @@ -61,6 +61,7 @@ export const nodeLibraryPackage = createFactory({ pluginVersion: ctx.defaultVersion, privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/pluginCommon.test.ts b/packages/cli/src/lib/new/factories/pluginCommon.test.ts index 82c1c87169..8f01401435 100644 --- a/packages/cli/src/lib/new/factories/pluginCommon.test.ts +++ b/packages/cli/src/lib/new/factories/pluginCommon.test.ts @@ -62,6 +62,7 @@ describe('pluginCommon factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); diff --git a/packages/cli/src/lib/new/factories/pluginCommon.ts b/packages/cli/src/lib/new/factories/pluginCommon.ts index 5f694124ea..eb17c70a5c 100644 --- a/packages/cli/src/lib/new/factories/pluginCommon.ts +++ b/packages/cli/src/lib/new/factories/pluginCommon.ts @@ -61,6 +61,7 @@ export const pluginCommon = createFactory({ privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, pluginVersion: ctx.defaultVersion, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/pluginNode.test.ts b/packages/cli/src/lib/new/factories/pluginNode.test.ts index d8d9ea33ab..b6aad0a129 100644 --- a/packages/cli/src/lib/new/factories/pluginNode.test.ts +++ b/packages/cli/src/lib/new/factories/pluginNode.test.ts @@ -62,6 +62,7 @@ describe('pluginNode factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); diff --git a/packages/cli/src/lib/new/factories/pluginNode.ts b/packages/cli/src/lib/new/factories/pluginNode.ts index c7f9ba6f6a..8eaab3cadb 100644 --- a/packages/cli/src/lib/new/factories/pluginNode.ts +++ b/packages/cli/src/lib/new/factories/pluginNode.ts @@ -61,6 +61,7 @@ export const pluginNode = createFactory({ privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, pluginVersion: ctx.defaultVersion, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/pluginWeb.test.ts b/packages/cli/src/lib/new/factories/pluginWeb.test.ts index ff4211d8fa..20fbbbbdb7 100644 --- a/packages/cli/src/lib/new/factories/pluginWeb.test.ts +++ b/packages/cli/src/lib/new/factories/pluginWeb.test.ts @@ -62,6 +62,7 @@ describe('pluginWeb factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); diff --git a/packages/cli/src/lib/new/factories/pluginWeb.ts b/packages/cli/src/lib/new/factories/pluginWeb.ts index dc8cb73dce..6635b0b0e1 100644 --- a/packages/cli/src/lib/new/factories/pluginWeb.ts +++ b/packages/cli/src/lib/new/factories/pluginWeb.ts @@ -61,6 +61,7 @@ export const pluginWeb = createFactory({ privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, pluginVersion: ctx.defaultVersion, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/scaffolderModule.test.ts b/packages/cli/src/lib/new/factories/scaffolderModule.test.ts index d83c2ce3f7..c4b9d78fc1 100644 --- a/packages/cli/src/lib/new/factories/scaffolderModule.test.ts +++ b/packages/cli/src/lib/new/factories/scaffolderModule.test.ts @@ -62,6 +62,7 @@ describe('scaffolderModule factory', () => { modified = true; }, createTemporaryDirectory: (name: string) => fs.mkdtemp(name), + license: 'Apache-2.0', }); expect(modified).toBe(true); diff --git a/packages/cli/src/lib/new/factories/scaffolderModule.ts b/packages/cli/src/lib/new/factories/scaffolderModule.ts index 07f67ce78c..4c279a49d4 100644 --- a/packages/cli/src/lib/new/factories/scaffolderModule.ts +++ b/packages/cli/src/lib/new/factories/scaffolderModule.ts @@ -78,6 +78,7 @@ export const scaffolderModule = createFactory({ privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, pluginVersion: ctx.defaultVersion, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts b/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts index b0c8461189..691f0b9f1c 100644 --- a/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts +++ b/packages/cli/src/lib/new/factories/webLibraryPackage.test.ts @@ -64,6 +64,7 @@ describe('webLibraryPackage factory', () => { modified = true; }, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(modified).toBe(true); @@ -134,6 +135,7 @@ describe('webLibraryPackage factory', () => { defaultVersion: '1.0.0', markAsModified: () => {}, createTemporaryDirectory: () => fs.mkdtemp('test'), + license: 'Apache-2.0', }); expect(Task.forCommand).toHaveBeenCalledTimes(2); diff --git a/packages/cli/src/lib/new/factories/webLibraryPackage.ts b/packages/cli/src/lib/new/factories/webLibraryPackage.ts index 45e1085ff3..3c63127d7d 100644 --- a/packages/cli/src/lib/new/factories/webLibraryPackage.ts +++ b/packages/cli/src/lib/new/factories/webLibraryPackage.ts @@ -61,6 +61,7 @@ export const webLibraryPackage = createFactory({ pluginVersion: ctx.defaultVersion, privatePackage: ctx.private, npmRegistry: ctx.npmRegistry, + license: ctx.license, }, }); diff --git a/packages/cli/src/lib/new/types.ts b/packages/cli/src/lib/new/types.ts index 6a894bf9ef..534f99f94f 100644 --- a/packages/cli/src/lib/new/types.ts +++ b/packages/cli/src/lib/new/types.ts @@ -27,6 +27,8 @@ export interface CreateContext { isMonoRepo: boolean; /** The default version to use for new packages */ defaultVersion: string; + /** License to use for new packages */ + license: string; /** Creates a temporary directory. This will always be deleted after creation is done. */ createTemporaryDirectory(name: string): Promise; diff --git a/packages/cli/src/lib/versioning/Lockfile.test.ts b/packages/cli/src/lib/versioning/Lockfile.test.ts index a4267acdb7..d6996b9143 100644 --- a/packages/cli/src/lib/versioning/Lockfile.test.ts +++ b/packages/cli/src/lib/versioning/Lockfile.test.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import fs from 'fs-extra'; -import { BackstagePackage } from '@backstage/cli-node'; import { Lockfile } from './Lockfile'; import { createMockDirectory } from '@backstage/backend-test-utils'; @@ -47,34 +45,6 @@ b@^2: version "2.0.0" `; -const mockADedup = `${LEGACY_HEADER} -a@^1: - version "1.0.1" - resolved "https://my-registry/a-1.0.01.tgz#abc123" - integrity sha512-xyz - dependencies: - b "^2" - -b@2.0.x, b@^2: - version "2.0.1" -`; - -const mockB = `${LEGACY_HEADER} -"@s/a@*", "@s/a@1 || 2", "@s/a@^1": - version "1.0.1" - -"@s/a@^2.0.x": - version "2.0.0" -`; - -const mockBDedup = `${LEGACY_HEADER} -"@s/a@*", "@s/a@1 || 2", "@s/a@^2.0.x": - version "2.0.0" - -"@s/a@^1": - version "1.0.1" -`; - describe('Lockfile', () => { const mockDir = createMockDirectory(); @@ -93,75 +63,6 @@ describe('Lockfile', () => { ]); expect(lockfile.toString()).toBe(mockA); }); - - it('should deduplicate and save mockA', async () => { - mockDir.setContent({ - 'yarn.lock': mockA, - }); - - const lockfilePath = mockDir.resolve('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ localPackages: new Map() }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [], - newVersions: [ - { - name: 'b', - range: '^2', - oldVersion: '2.0.0', - newVersion: '2.0.1', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockA); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockADedup); - - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockA); - await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockADedup); - }); - - it('should deduplicate mockB', async () => { - mockDir.setContent({ - 'yarn.lock': mockB, - }); - - const lockfile = await Lockfile.load(mockDir.resolve('yarn.lock')); - const result = lockfile.analyze({ localPackages: new Map() }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [ - { - name: '@s/a', - oldRange: '^1', - newRange: '^2.0.x', - oldVersion: '1.0.1', - newVersion: '2.0.0', - }, - ], - newVersions: [ - { - name: '@s/a', - range: '*', - oldVersion: '1.0.1', - newVersion: '2.0.0', - }, - { - name: '@s/a', - range: '1 || 2', - oldVersion: '1.0.1', - newVersion: '2.0.0', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockB); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockBDedup); - }); }); const mockANew = `${MODERN_HEADER} @@ -179,51 +80,6 @@ b@^2: version: 2.0.0 `; -const mockANewDedup = `${MODERN_HEADER} -a@^1: - version: 1.0.1 - dependencies: - b: ^2 - integrity: sha512-xyz - resolved: "https://my-registry/a-1.0.01.tgz#abc123" - -"b@2.0.x, b@^2.0.1": - version: 2.0.1 - -b@^2: - version: 2.0.1 -`; - -const mockANewLocal = `${MODERN_HEADER} -a@^1: - version: 1.0.1 - dependencies: - b: ^2 - integrity: sha512-xyz - resolved: "https://my-registry/a-1.0.01.tgz#abc123" - -"b@2.0.x, b@^2.0.1": - version: 0.0.0-use.local - -b@^2: - version: 2.0.0 -`; - -const mockANewLocalDedup = `${MODERN_HEADER} -a@^1: - version: 1.0.1 - dependencies: - b: ^2 - integrity: sha512-xyz - resolved: "https://my-registry/a-1.0.01.tgz#abc123" - -"b@2.0.x, b@^2.0.1": - version: 0.0.0-use.local - -b@^2: - version: 0.0.0-use.local -`; - describe('New Lockfile', () => { const mockDir = createMockDirectory(); @@ -243,79 +99,4 @@ describe('New Lockfile', () => { ]); expect(lockfile.toString()).toBe(mockANew); }); - - it('should deduplicate and save mockANew', async () => { - mockDir.setContent({ - 'yarn.lock': mockANew, - }); - - const lockfilePath = mockDir.resolve('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ localPackages: new Map() }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [], - newVersions: [ - { - name: 'b', - range: '^2', - oldVersion: '2.0.0', - newVersion: '2.0.1', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockANew); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockANewDedup); - - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockANew); - await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( - mockANewDedup, - ); - }); - - it('should deduplicate and save mockANewLocal', async () => { - mockDir.setContent({ - 'yarn.lock': mockANewLocal, - }); - - const lockfilePath = mockDir.resolve('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ - localPackages: new Map([ - [ - 'b', - { - packageJson: { version: '2.0.1' }, - } as BackstagePackage, - ], - ]), - }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [], - newVersions: [ - { - name: 'b', - range: '^2', - oldVersion: '2.0.0', - newVersion: '0.0.0-use.local', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockANewLocal); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockANewLocalDedup); - - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( - mockANewLocal, - ); - await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( - mockANewLocalDedup, - ); - }); }); diff --git a/packages/cli/src/lib/versioning/Lockfile.ts b/packages/cli/src/lib/versioning/Lockfile.ts index 50d0a77cfd..047cf5aefc 100644 --- a/packages/cli/src/lib/versioning/Lockfile.ts +++ b/packages/cli/src/lib/versioning/Lockfile.ts @@ -15,10 +15,8 @@ */ import fs from 'fs-extra'; -import semver from 'semver'; import { parseSyml, stringifySyml } from '@yarnpkg/parsers'; import { stringify as legacyStringifyLockfile } from '@yarnpkg/lockfile'; -import { BackstagePackage } from '@backstage/cli-node'; const ENTRY_PATTERN = /^((?:@[^/]+\/)?[^@/]+)@(.+)$/; @@ -39,35 +37,6 @@ type LockfileQueryEntry = { dataKey: string; }; -/** Entries that have an invalid version range, for example an npm tag */ -type AnalyzeResultInvalidRange = { - name: string; - range: string; -}; - -/** Entries that can be deduplicated by bumping to an existing higher version */ -type AnalyzeResultNewVersion = { - name: string; - range: string; - oldVersion: string; - newVersion: string; -}; - -/** Entries that would need a dependency update in package.json to be deduplicated */ -type AnalyzeResultNewRange = { - name: string; - oldRange: string; - newRange: string; - oldVersion: string; - newVersion: string; -}; - -type AnalyzeResult = { - invalidRanges: AnalyzeResultInvalidRange[]; - newVersions: AnalyzeResultNewVersion[]; - newRanges: AnalyzeResultNewRange[]; -}; - // the new yarn header is handled out of band of the parsing // https://github.com/yarnpkg/berry/blob/0c5974f193a9397630e9aee2b3876cca62611149/packages/yarnpkg-core/sources/Project.ts#L1741-L1746 const NEW_HEADER = `${[ @@ -153,186 +122,6 @@ export class Lockfile { return this.packages.keys(); } - /** Analyzes the lockfile to identify possible actions and warnings for the entries */ - analyze(options: { - filter?: (name: string) => boolean; - localPackages: Map; - }): AnalyzeResult { - const { filter, localPackages } = options; - const result: AnalyzeResult = { - invalidRanges: [], - newVersions: [], - newRanges: [], - }; - - for (const [name, allEntries] of this.packages) { - if (filter && !filter(name)) { - continue; - } - - // Get rid of and signal any invalid ranges upfront - const invalid = allEntries.filter( - e => !semver.validRange(e.range) && !e.range.startsWith('workspace:'), - ); - result.invalidRanges.push( - ...invalid.map(({ range }) => ({ name, range })), - ); - - // Grab all valid entries, if there aren't at least 2 different valid ones we're done - const entries = allEntries.filter(e => semver.validRange(e.range)); - if (entries.length < 2) { - continue; - } - - // Find all versions currently in use - const versions = Array.from(new Set(entries.map(e => e.version))) - .map(v => { - // Translate workspace:^ references to the actual version - if (v === '0.0.0-use.local') { - const local = localPackages.get(name); - if (!local) { - throw new Error(`No local package found for ${name}`); - } - if (!local.packageJson.version) { - throw new Error(`No version found for local package ${name}`); - } - return { - entryVersion: v, - actualVersion: local.packageJson.version, - }; - } - return { entryVersion: v, actualVersion: v }; - }) - .sort((v1, v2) => semver.rcompare(v1.actualVersion, v2.actualVersion)); - - // If we're not using at least 2 different versions we're done - if (versions.length < 2) { - continue; - } - - // TODO(Rugvip): Support bumping into workspace ranges too - const acceptedVersions = new Set(); - for (const { version, range } of entries) { - // Finds the highest matching version from the the known versions - // TODO(Rugvip): We may want to select the version that satisfies the most ranges rather than the highest one - const acceptedVersion = versions.find(v => - semver.satisfies(v.actualVersion, range), - ); - if (!acceptedVersion) { - throw new Error( - `No existing version was accepted for range ${range}, searching through ${versions}, for package ${name}`, - ); - } - - if (acceptedVersion.entryVersion !== version) { - result.newVersions.push({ - name, - range, - newVersion: acceptedVersion.entryVersion, - oldVersion: version, - }); - } - - acceptedVersions.add(acceptedVersion.actualVersion); - } - - // If all ranges were able to accept the same version, we're done - if (acceptedVersions.size === 1) { - continue; - } - - // Find the max version that we may want bump older packages to - const maxVersion = Array.from(acceptedVersions).sort(semver.rcompare)[0]; - // Find all existing ranges that satisfy the new max version, and pick the one that - // results in the highest minimum allowed version, usually being the more specific one - const maxEntry = entries - .filter(e => semver.satisfies(maxVersion, e.range)) - .map(e => ({ e, min: semver.minVersion(e.range) })) - .filter(p => p.min) - .sort((a, b) => semver.rcompare(a.min!, b.min!))[0]?.e; - if (!maxEntry) { - throw new Error( - `No entry found that satisfies max version '${maxVersion}'`, - ); - } - - // Find all entries that don't satisfy the max version - for (const { version, range } of entries) { - if (semver.satisfies(maxVersion, range)) { - continue; - } - - result.newRanges.push({ - name, - oldRange: range, - newRange: maxEntry.range, - oldVersion: version, - newVersion: maxVersion, - }); - } - } - - return result; - } - - remove(name: string, range: string): boolean { - const query = `${name}@${range}`; - const existed = Boolean(this.data[query]); - delete this.data[query]; - - const newEntries = this.packages.get(name)?.filter(e => e.range !== range); - if (newEntries) { - this.packages.set(name, newEntries); - } - - return existed; - } - - /** Modifies the lockfile by bumping packages to the suggested versions */ - replaceVersions(results: AnalyzeResultNewVersion[]) { - for (const { name, range, oldVersion, newVersion } of results) { - const query = `${name}@${range}`; - - // Update the backing data - const entryData = this.data[query]; - if (!entryData) { - throw new Error(`No entry data for ${query}`); - } - if (entryData.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - - // Modifying the data in the entry is not enough, we need to reference an existing version object - const matchingEntry = Object.entries(this.data).find( - ([q, e]) => q.startsWith(`${name}@`) && e.version === newVersion, - ); - if (!matchingEntry) { - throw new Error( - `No matching entry found for ${name} at version ${newVersion}`, - ); - } - this.data[query] = matchingEntry[1]; - - // Update our internal data structure - const entry = this.packages.get(name)?.find(e => e.range === range); - if (!entry) { - throw new Error(`No entry data for ${query}`); - } - if (entry.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - entry.version = newVersion; - } - } - - async save(path: string) { - await fs.writeFile(path, this.toString(), 'utf8'); - } - toString() { return this.legacy ? legacyStringifyLockfile(this.data) diff --git a/packages/cli/templates/default-backend-module/package.json.hbs b/packages/cli/templates/default-backend-module/package.json.hbs index 07eee73d50..db8b8749b3 100644 --- a/packages/cli/templates/default-backend-module/package.json.hbs +++ b/packages/cli/templates/default-backend-module/package.json.hbs @@ -4,7 +4,7 @@ "version": "{{packageVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/cli/templates/default-backend-plugin/package.json.hbs b/packages/cli/templates/default-backend-plugin/package.json.hbs index 3b808fc5e5..b05d1a844b 100644 --- a/packages/cli/templates/default-backend-plugin/package.json.hbs +++ b/packages/cli/templates/default-backend-plugin/package.json.hbs @@ -3,7 +3,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} @@ -31,7 +31,6 @@ "@backstage/backend-common": "{{versionQuery '@backstage/backend-common'}}", "@backstage/backend-defaults": "{{versionQuery '@backstage/backend-defaults'}}", "@backstage/backend-plugin-api": "{{versionQuery '@backstage/backend-plugin-api'}}", - "@backstage/config": "{{versionQuery '@backstage/config'}}", "express": "{{versionQuery 'express' '4.17.1'}}", "express-promise-router": "{{versionQuery 'express-promise-router' '4.1.0'}}", "node-fetch": "{{versionQuery 'node-fetch' '2.6.7'}}" diff --git a/packages/cli/templates/default-backend-plugin/src/service/router.ts b/packages/cli/templates/default-backend-plugin/src/service/router.ts index 312d7e252e..ced654aa82 100644 --- a/packages/cli/templates/default-backend-plugin/src/service/router.ts +++ b/packages/cli/templates/default-backend-plugin/src/service/router.ts @@ -1,12 +1,11 @@ import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; -import { LoggerService } from '@backstage/backend-plugin-api'; -import { Config } from '@backstage/config'; +import { LoggerService, RootConfigService } from '@backstage/backend-plugin-api'; import express from 'express'; import Router from 'express-promise-router'; export interface RouterOptions { logger: LoggerService; - config: Config; + config: RootConfigService; } export async function createRouter( diff --git a/packages/cli/templates/default-common-plugin-package/package.json.hbs b/packages/cli/templates/default-common-plugin-package/package.json.hbs index 992599ef6d..689c3e6f53 100644 --- a/packages/cli/templates/default-common-plugin-package/package.json.hbs +++ b/packages/cli/templates/default-common-plugin-package/package.json.hbs @@ -4,7 +4,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/cli/templates/default-node-plugin-package/package.json.hbs b/packages/cli/templates/default-node-plugin-package/package.json.hbs index 45becd1bea..d58f95b3b2 100644 --- a/packages/cli/templates/default-node-plugin-package/package.json.hbs +++ b/packages/cli/templates/default-node-plugin-package/package.json.hbs @@ -4,7 +4,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index c833c125f6..b4034fd742 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -3,7 +3,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs b/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs index 9db62feebc..c79977f301 100644 --- a/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs +++ b/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs @@ -4,14 +4,14 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { screen } from '@testing-library/react'; import { - setupRequestMockHandlers, + registerMswTestHooks, renderInTestApp, } from '@backstage/test-utils'; describe('ExampleComponent', () => { const server = setupServer(); // Enable sane handlers for network requests - setupRequestMockHandlers(server); + registerMswTestHooks(server); // setup mock response beforeEach(() => { diff --git a/packages/cli/templates/default-react-plugin-package/package.json.hbs b/packages/cli/templates/default-react-plugin-package/package.json.hbs index 79f3430f46..bea066630f 100644 --- a/packages/cli/templates/default-react-plugin-package/package.json.hbs +++ b/packages/cli/templates/default-react-plugin-package/package.json.hbs @@ -4,7 +4,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/cli/templates/node-library-package/package.json.hbs b/packages/cli/templates/node-library-package/package.json.hbs index a6ede31893..d56a51bcd6 100644 --- a/packages/cli/templates/node-library-package/package.json.hbs +++ b/packages/cli/templates/node-library-package/package.json.hbs @@ -3,7 +3,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/cli/templates/scaffolder-module/package.json.hbs b/packages/cli/templates/scaffolder-module/package.json.hbs index 0ebe5dd5f4..df4bf352f4 100644 --- a/packages/cli/templates/scaffolder-module/package.json.hbs +++ b/packages/cli/templates/scaffolder-module/package.json.hbs @@ -4,7 +4,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/cli/templates/web-library-package/package.json.hbs b/packages/cli/templates/web-library-package/package.json.hbs index 271417a525..64a693dd4c 100644 --- a/packages/cli/templates/web-library-package/package.json.hbs +++ b/packages/cli/templates/web-library-package/package.json.hbs @@ -3,7 +3,7 @@ "version": "{{pluginVersion}}", "main": "src/index.ts", "types": "src/index.ts", - "license": "Apache-2.0", + "license": "{{license}}", {{#if privatePackage}} "private": {{privatePackage}}, {{/if}} diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index fb048e7237..78f2123970 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/config-loader +## 1.9.0-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 1.9.0-next.1 + +### Minor Changes + +- 274428f: Add configuration key to File and Remote `ConfigSource`s that enables configuration of parsing logic. Previously limited to yaml, these `ConfigSource`s now allow for a multitude of parsing options (e.g. JSON). + +### Patch Changes + +- 1edd6c2: The `env` option of `ConfigSources.default` now correctly allows undefined members. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 1.8.2-next.0 + +### Patch Changes + +- 493feac: Add boolean `allowMissingDefaultConfig` option to `ConfigSources.default` and + `ConfigSources.defaultForTargets`, which results in omission of a ConfigSource + for the default app-config.yaml configuration file if it's not present. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.8.1 ### Patch Changes diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index bc8f217bbb..e2741d609c 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -21,6 +21,7 @@ export type AsyncConfigSourceGenerator = AsyncGenerator< // @public export interface BaseConfigSourcesOptions { + allowMissingDefaultConfig?: boolean; // (undocumented) remote?: Pick; // (undocumented) @@ -87,7 +88,7 @@ export interface ConfigSourcesDefaultOptions extends BaseConfigSourcesOptions { // (undocumented) argv?: string[]; // (undocumented) - env?: Record; + env?: Record; } // @public @@ -141,6 +142,7 @@ export class FileConfigSource implements ConfigSource { // @public export interface FileConfigSourceOptions { + parser?: Parser; path: string; substitutionFunc?: EnvFunc; watch?: boolean; @@ -218,6 +220,11 @@ export interface MutableConfigSourceOptions { data?: JsonObject; } +// @public +export type Parser = ({ contents }: { contents: string }) => Promise<{ + result?: JsonObject; +}>; + // @public export interface ReadConfigDataOptions { // (undocumented) @@ -242,6 +249,7 @@ export class RemoteConfigSource implements ConfigSource { // @public export interface RemoteConfigSourceOptions { + parser?: Parser; reloadInterval?: HumanDuration; substitutionFunc?: EnvFunc; url: string; diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 28718b8290..a47a17c12f 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/config-loader", - "version": "1.8.1", + "version": "1.9.0-next.2", "description": "Config loading functionality used by Backstage backend, and CLI", "backstage": { "role": "node-library" @@ -49,7 +49,7 @@ "json-schema-traverse": "^1.0.0", "lodash": "^4.17.21", "minimist": "^1.2.5", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "typescript-json-schema": "^0.63.0", "yaml": "^2.0.0" }, diff --git a/packages/config-loader/src/sources/ConfigSources.test.ts b/packages/config-loader/src/sources/ConfigSources.test.ts index 4b14572666..e19ac1d51f 100644 --- a/packages/config-loader/src/sources/ConfigSources.test.ts +++ b/packages/config-loader/src/sources/ConfigSources.test.ts @@ -69,13 +69,18 @@ describe('ConfigSources', () => { }); it('should create default sources for targets', () => { + const fsSpy = jest.spyOn(fs, 'pathExistsSync').mockImplementation(path => { + return path === `${root}app-config.yaml`; + }); + expect( mergeSources( ConfigSources.defaultForTargets({ rootDir: '/', targets: [] }), ), ).toEqual([{ name: 'FileConfigSource', path: `${root}app-config.yaml` }]); - const fsSpy = jest.spyOn(fs, 'pathExistsSync').mockReturnValue(true); + fsSpy.mockReturnValue(true); + expect( mergeSources( ConfigSources.defaultForTargets({ rootDir: '/', targets: [] }), @@ -159,6 +164,10 @@ describe('ConfigSources', () => { }); it('should create a default source', () => { + const fsSpy = jest.spyOn(fs, 'pathExistsSync').mockImplementation(path => { + return path === `${root}app-config.yaml`; + }); + expect( mergeSources( ConfigSources.default({ @@ -184,6 +193,8 @@ describe('ConfigSources', () => { { name: 'FileConfigSource', path: resolvePath('b.yaml') }, { name: 'EnvConfigSource', env: { HOME: '/' } }, ]); + + fsSpy.mockRestore(); }); it('should merge sources', () => { diff --git a/packages/config-loader/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index ecff39da2d..37c1c6b087 100644 --- a/packages/config-loader/src/sources/ConfigSources.ts +++ b/packages/config-loader/src/sources/ConfigSources.ts @@ -74,6 +74,11 @@ export interface BaseConfigSourcesOptions { watch?: boolean; rootDir?: string; remote?: Pick; + /** + * Allow the default app-config.yaml to be missing, in which case the source + * will not be created. + */ + allowMissingDefaultConfig?: boolean; /** * A custom substitution function that overrides the default one. @@ -102,7 +107,7 @@ export interface ConfigSourcesDefaultForTargetsOptions */ export interface ConfigSourcesDefaultOptions extends BaseConfigSourcesOptions { argv?: string[]; - env?: Record; + env?: Record; } /** @@ -177,14 +182,19 @@ export class ConfigSources { if (argSources.length === 0) { const defaultPath = resolvePath(rootDir, 'app-config.yaml'); const localPath = resolvePath(rootDir, 'app-config.local.yaml'); + const alwaysIncludeDefaultConfigSource = + !options.allowMissingDefaultConfig; + + if (alwaysIncludeDefaultConfigSource || fs.pathExistsSync(defaultPath)) { + argSources.push( + FileConfigSource.create({ + watch: options.watch, + path: defaultPath, + substitutionFunc: options.substitutionFunc, + }), + ); + } - argSources.push( - FileConfigSource.create({ - watch: options.watch, - path: defaultPath, - substitutionFunc: options.substitutionFunc, - }), - ); if (fs.pathExistsSync(localPath)) { argSources.push( FileConfigSource.create({ diff --git a/packages/config-loader/src/sources/FileConfigSource.test.ts b/packages/config-loader/src/sources/FileConfigSource.test.ts index 61cdeed272..4ed31ccee0 100644 --- a/packages/config-loader/src/sources/FileConfigSource.test.ts +++ b/packages/config-loader/src/sources/FileConfigSource.test.ts @@ -59,6 +59,19 @@ describe('FileConfigSource', () => { ]); }); + it('should read a config file with optional parser', async () => { + const tmp = await tmpFiles({ 'a.json': JSON.stringify({ a: 1 }) }); + + const source = FileConfigSource.create({ + path: tmp.resolve('a.json'), + parser: async ({ contents }) => ({ result: JSON.parse(contents) }), + }); + + await expect(readN(source, 1)).resolves.toEqual([ + [{ data: { a: 1 }, context: 'a.json', path: tmp.resolve('a.json') }], + ]); + }); + it('should watch config files', async () => { const tmp = await tmpFiles({ 'a.yaml': 'a: 1' }); diff --git a/packages/config-loader/src/sources/FileConfigSource.ts b/packages/config-loader/src/sources/FileConfigSource.ts index 74266de227..c0697c1180 100644 --- a/packages/config-loader/src/sources/FileConfigSource.ts +++ b/packages/config-loader/src/sources/FileConfigSource.ts @@ -17,16 +17,17 @@ import chokidar, { FSWatcher } from 'chokidar'; import fs from 'fs-extra'; import { basename, dirname, isAbsolute, resolve as resolvePath } from 'path'; -import yaml from 'yaml'; import { AsyncConfigSourceGenerator, ConfigSource, ConfigSourceData, SubstitutionFunc, + Parser, ReadConfigDataOptions, } from './types'; import { createConfigTransformer } from './transform'; import { NotFoundError } from '@backstage/errors'; +import { parseYamlContent } from './utils'; /** * Options for {@link FileConfigSource.create}. @@ -48,6 +49,11 @@ export interface FileConfigSourceOptions { * A substitution function to use instead of the default environment substitution. */ substitutionFunc?: SubstitutionFunc; + + /** + * A content parsing function to transform string content to configuration values. + */ + parser?: Parser; } async function readFile(path: string): Promise { @@ -95,11 +101,13 @@ export class FileConfigSource implements ConfigSource { readonly #path: string; readonly #substitutionFunc?: SubstitutionFunc; readonly #watch?: boolean; + readonly #parser: Parser; private constructor(options: FileConfigSourceOptions) { this.#path = options.path; this.#substitutionFunc = options.substitutionFunc; this.#watch = options.watch ?? true; + this.#parser = options.parser ?? parseYamlContent; } // Work is duplicated across each read, in practice that should not @@ -154,12 +162,12 @@ export class FileConfigSource implements ConfigSource { watchedPaths.push(this.#path); } - const content = await readFile(this.#path); - if (content === undefined) { + const contents = await readFile(this.#path); + if (contents === undefined) { throw new NotFoundError(`Config file "${this.#path}" does not exist`); } - const parsed = yaml.parse(content); - if (parsed === null) { + const { result: parsed } = await this.#parser({ contents }); + if (parsed === undefined) { return []; } try { diff --git a/packages/config-loader/src/sources/RemoteConfigSource.test.ts b/packages/config-loader/src/sources/RemoteConfigSource.test.ts index 6082c05e65..372dc91823 100644 --- a/packages/config-loader/src/sources/RemoteConfigSource.test.ts +++ b/packages/config-loader/src/sources/RemoteConfigSource.test.ts @@ -15,14 +15,14 @@ */ import { rest } from 'msw'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { RemoteConfigSource } from './RemoteConfigSource'; import { readN } from './__testUtils__/testUtils'; describe('RemoteConfigSource', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); it('should load config from a remote URL', async () => { worker.use( @@ -59,6 +59,45 @@ app: ]); }); + it('should load and parse config from a remote URL', async () => { + worker.use( + rest.get('http://localhost/config.json', (_req, res, ctx) => + res( + ctx.body( + JSON.stringify({ + app: { + title: 'Example App', + substituted: 'x', + escaped: '$${VALUE}', + }, + }), + ), + ), + ), + ); + + const source = RemoteConfigSource.create({ + url: 'http://localhost/config.json', + substitutionFunc: async () => 'x', + parser: async ({ contents }) => ({ result: JSON.parse(contents) }), + }); + + await expect(readN(source, 1)).resolves.toEqual([ + [ + { + context: 'http://localhost/config.json', + data: { + app: { + title: 'Example App', + substituted: 'x', + escaped: '${VALUE}', + }, + }, + }, + ], + ]); + }); + it('should reload config from a remote URL', async () => { let fetched = false; diff --git a/packages/config-loader/src/sources/RemoteConfigSource.ts b/packages/config-loader/src/sources/RemoteConfigSource.ts index 10a64ee635..1492cd4d28 100644 --- a/packages/config-loader/src/sources/RemoteConfigSource.ts +++ b/packages/config-loader/src/sources/RemoteConfigSource.ts @@ -22,14 +22,15 @@ import { } from '@backstage/types'; import isEqual from 'lodash/isEqual'; import fetch from 'node-fetch'; -import yaml from 'yaml'; import { ConfigTransformer, createConfigTransformer } from './transform'; import { AsyncConfigSourceGenerator, ConfigSource, SubstitutionFunc, ReadConfigDataOptions, + Parser, } from './types'; +import { parseYamlContent } from './utils'; const DEFAULT_RELOAD_INTERVAL = { seconds: 60 }; @@ -55,6 +56,11 @@ export interface RemoteConfigSourceOptions { * A substitution function to use instead of the default environment substitution. */ substitutionFunc?: SubstitutionFunc; + + /** + * A content parsing function to transform string content to configuration values. + */ + parser?: Parser; } /** @@ -84,6 +90,7 @@ export class RemoteConfigSource implements ConfigSource { readonly #url: string; readonly #reloadIntervalMs: number; readonly #transformer: ConfigTransformer; + readonly #parser: Parser; private constructor(options: RemoteConfigSourceOptions) { this.#url = options.url; @@ -93,6 +100,7 @@ export class RemoteConfigSource implements ConfigSource { this.#transformer = createConfigTransformer({ substitutionFunc: options.substitutionFunc, }); + this.#parser = options.parser ?? parseYamlContent; } async *readConfigData( @@ -135,11 +143,21 @@ export class RemoteConfigSource implements ConfigSource { throw await ResponseError.fromResponse(res); } - const content = await res.text(); - const data = await this.#transformer(yaml.parse(content)); - if (data === null) { + const contents = await res.text(); + const { result: rawData } = await this.#parser({ contents }); + if (rawData === undefined) { + /** + * This error message is/was coupled to the implementation and with refactoring it is no longer truly accurate + * This behavior is also inconsistent with {@link FileConfigSource}, which doesn't error on unparseable or empty + * content + * + * Preserving to not make a breaking change + */ throw new Error('configuration data is null'); - } else if (typeof data !== 'object') { + } + + const data = await this.#transformer(rawData); + if (typeof data !== 'object') { throw new Error('configuration data is not an object'); } else if (Array.isArray(data)) { throw new Error( diff --git a/packages/config-loader/src/sources/index.ts b/packages/config-loader/src/sources/index.ts index a25f689b40..3bf8e71990 100644 --- a/packages/config-loader/src/sources/index.ts +++ b/packages/config-loader/src/sources/index.ts @@ -38,4 +38,5 @@ export type { ConfigSourceData, ReadConfigDataOptions, AsyncConfigSourceGenerator, + Parser, } from './types'; diff --git a/packages/config-loader/src/sources/types.ts b/packages/config-loader/src/sources/types.ts index dec6f415f2..abdf2f5c8e 100644 --- a/packages/config-loader/src/sources/types.ts +++ b/packages/config-loader/src/sources/types.ts @@ -15,6 +15,7 @@ */ import { AppConfig } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; /** * The data returned by {@link ConfigSource.readConfigData}. @@ -89,3 +90,18 @@ export interface ConfigSource { * @public */ export type SubstitutionFunc = (name: string) => Promise; + +/** + * A custom function to be used for parsing configuration content. + * + * @remarks + * + * The default parsing function will parse configuration content as yaml. + * + * @public + */ +export type Parser = ({ + contents, +}: { + contents: string; +}) => Promise<{ result?: JsonObject }>; diff --git a/packages/config-loader/src/sources/utils.ts b/packages/config-loader/src/sources/utils.ts index 9978234195..b948cc47b4 100644 --- a/packages/config-loader/src/sources/utils.ts +++ b/packages/config-loader/src/sources/utils.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { Parser } from './types'; +import yaml from 'yaml'; + /** @internal */ export interface SimpleDeferred { promise: Promise; @@ -55,3 +58,9 @@ export async function waitOrAbort( signals.forEach(s => s.addEventListener('abort', onAbort)); }); } + +/** @internal */ +export const parseYamlContent: Parser = async ({ contents }) => { + const parsed = yaml.parse(contents); + return { result: parsed === null ? undefined : parsed }; +}; diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index d80ed2fdcb..26b9eb20fe 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/core-app-api +## 1.14.1-next.0 + +### Patch Changes + +- 9a46a81: The request to delete the session cookie when running the app in protected mode is now done with a plain `fetch` rather than `FetchApi`. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## 1.14.0 + +### Minor Changes + +- d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets. + + ```yaml + app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false + ``` + +### Patch Changes + +- db2e2d5: Updated config schema to support app.routes.bindings +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.13.1-next.1 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 35e32f9726..6a107e0a87 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "1.13.1-next.1", + "version": "1.14.2-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts index 92e2abffb7..941ec90d66 100644 --- a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts @@ -153,8 +153,9 @@ export class AppIdentityProxy implements IdentityApi { // It is fine if we do NOT worry yet about deleting cookies for OTHER backends like techdocs const appBaseUrl = await ctx.discoveryApi.getBaseUrl('app'); try { - await ctx.fetchApi.fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, { + await fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, { method: 'DELETE', + credentials: 'include', }); } catch { // Ignore the error for those who use static serving of the frontend diff --git a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts index b6d59bd3f2..0143aa2ded 100644 --- a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts @@ -19,13 +19,13 @@ import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; import { ConfigReader } from '@backstage/config'; import { microsoftAuthApiRef } from '@backstage/core-plugin-api'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; describe('MicrosoftAuth', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); const microsoftAuth = MicrosoftAuth.create({ configApi: new ConfigReader(undefined), oauthRequestApi: new MockOAuthApi(), diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 85b6bcd684..01277a09c7 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -19,9 +19,12 @@ import { MockAnalyticsApi, renderWithEffects, withLogCollector, + registerMswTestHooks, } from '@backstage/test-utils'; -import { screen, waitFor, act } from '@testing-library/react'; +import { screen, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { setupServer } from 'msw/node'; +import { rest } from 'msw'; import React, { PropsWithChildren, ReactNode } from 'react'; import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; import { @@ -51,6 +54,9 @@ import { } from '@backstage/core-plugin-api/alpha'; describe('Integration Test', () => { + const server = setupServer(); + registerMswTestHooks(server); + const noOpAnalyticsApi = createApiFactory( analyticsApiRef, new NoOpAnalyticsApi(), @@ -847,6 +853,17 @@ describe('Integration Test', () => { }); it('should clear app cookie when the user logs out', async () => { + const logoutSignal = jest.fn(); + server.use( + rest.delete( + 'http://localhost:7007/app/.backstage/auth/v1/cookie', + (_req, res, ctx) => { + logoutSignal(); + return res(ctx.status(200)); + }, + ), + ); + const meta = global.document.createElement('meta'); meta.name = 'backstage-app-mode'; meta.content = 'protected'; @@ -901,12 +918,7 @@ describe('Integration Test', () => { await userEvent.click(screen.getByText('Sign Out')); }); - await waitFor(() => - expect(fetchApiMock.fetch).toHaveBeenCalledWith( - 'http://localhost:7007/app/.backstage/auth/v1/cookie', - { method: 'DELETE' }, - ), - ); + expect(logoutSignal).toHaveBeenCalled(); global.document.head.removeChild(meta); }); diff --git a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts index 4273ea99ee..60c4a3b8d9 100644 --- a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts +++ b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts @@ -18,7 +18,7 @@ import { DefaultAuthConnector } from './DefaultAuthConnector'; import MockOAuthApi from '../../apis/implementations/OAuthRequestApi/MockOAuthApi'; import * as loginPopup from '../loginPopup'; import { UrlPatternDiscovery } from '../../apis'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -53,7 +53,7 @@ const defaultOptions = { describe('DefaultAuthConnector', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.resetAllMocks(); diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 3ad2bd654e..34c134f731 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/core-compat-api +## 0.2.8-next.2 + +### Patch Changes + +- 72754db: Updated usage of `useRouteRef`, which can now always return `undefined`. +- 16cf96c: Both `compatWrapper` and `convertLegacyRouteRef` now support converting from the new system to the old. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## 0.2.8-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## 0.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + ## 0.2.7-next.1 ### Patch Changes diff --git a/packages/core-compat-api/api-report.md b/packages/core-compat-api/api-report.md index be80ca50e9..8d177b4dab 100644 --- a/packages/core-compat-api/api-report.md +++ b/packages/core-compat-api/api-report.md @@ -37,12 +37,24 @@ export function convertLegacyRouteRef( ): SubRouteRef_2; // @public -export function convertLegacyRouteRef< - TParams extends AnyRouteRefParams, - TOptional extends boolean, ->( - ref: ExternalRouteRef, -): ExternalRouteRef_2; +export function convertLegacyRouteRef( + ref: ExternalRouteRef, +): ExternalRouteRef_2; + +// @public +export function convertLegacyRouteRef( + ref: RouteRef_2, +): RouteRef; + +// @public +export function convertLegacyRouteRef( + ref: SubRouteRef_2, +): SubRouteRef; + +// @public +export function convertLegacyRouteRef( + ref: ExternalRouteRef_2, +): ExternalRouteRef; // @public export function convertLegacyRouteRefs< @@ -75,8 +87,8 @@ export type ToNewRouteRef = ? RouteRef_2 : T extends SubRouteRef ? SubRouteRef_2 - : T extends ExternalRouteRef - ? ExternalRouteRef_2 + : T extends ExternalRouteRef + ? ExternalRouteRef_2 : never; // (No @packageDocumentation comment for this package) diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index 0f164a6187..0434b206d9 100644 --- a/packages/core-compat-api/package.json +++ b/packages/core-compat-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-compat-api", - "version": "0.2.7-next.1", + "version": "0.2.8-next.2", "backstage": { "role": "web-library" }, @@ -44,6 +44,7 @@ "@backstage/frontend-app-api": "workspace:^", "@backstage/frontend-test-utils": "workspace:^", "@backstage/plugin-catalog": "workspace:^", + "@backstage/test-utils": "workspace:^", "@oriflame/backstage-plugin-score-card": "^0.8.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^15.0.0" diff --git a/packages/core-compat-api/src/collectLegacyRoutes.tsx b/packages/core-compat-api/src/collectLegacyRoutes.tsx index b9f4e5528c..3523b0a40b 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.tsx @@ -101,7 +101,7 @@ function visitRouteChildren(options: { parentExtensionId: string; context: { pluginId: string; - extensions: ExtensionDefinition[]; + extensions: ExtensionDefinition[]; getUniqueName: () => string; discoverPlugin: (plugin: LegacyBackstagePlugin) => void; }; @@ -154,7 +154,7 @@ export function collectLegacyRoutes( ): BackstagePlugin[] { const pluginExtensions = new Map< LegacyBackstagePlugin, - ExtensionDefinition[] + ExtensionDefinition[] >(); const getUniqueName = (() => { diff --git a/packages/core-compat-api/src/compatWrapper/BackwardsCompatProvider.tsx b/packages/core-compat-api/src/compatWrapper/BackwardsCompatProvider.tsx index 288f3f900b..4f9ba3a836 100644 --- a/packages/core-compat-api/src/compatWrapper/BackwardsCompatProvider.tsx +++ b/packages/core-compat-api/src/compatWrapper/BackwardsCompatProvider.tsx @@ -50,7 +50,9 @@ const legacyPluginStore = getOrCreateGlobalSingleton( () => new WeakMap(), ); -function toLegacyPlugin(plugin: NewBackstagePlugin): LegacyBackstagePlugin { +export function toLegacyPlugin( + plugin: NewBackstagePlugin, +): LegacyBackstagePlugin { let legacy = legacyPluginStore.get(plugin); if (legacy) { return legacy; diff --git a/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx b/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx index 5544862aee..9c646d5b00 100644 --- a/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx +++ b/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx @@ -14,10 +14,155 @@ * limitations under the License. */ -import React from 'react'; +import { + ApiHolder, + ApiRef, + AppContext, + useApp, +} from '@backstage/core-plugin-api'; +import { + AnyRouteRefParams, + ComponentRef, + ComponentsApi, + CoreErrorBoundaryFallbackProps, + CoreNotFoundErrorPageProps, + CoreProgressProps, + ExternalRouteRef, + IconComponent, + IconsApi, + RouteFunc, + RouteRef, + RouteResolutionApi, + RouteResolutionApiResolveOptions, + SubRouteRef, + componentsApiRef, + coreComponentRefs, + iconsApiRef, + routeResolutionApiRef, +} from '@backstage/frontend-plugin-api'; +import React, { ComponentType, useMemo } from 'react'; import { ReactNode } from 'react'; +import { toLegacyPlugin } from './BackwardsCompatProvider'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { ApiProvider } from '../../../core-app-api/src/apis/system/ApiProvider'; +import { useVersionedContext } from '@backstage/version-bridge'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { type RouteResolver } from '../../../core-plugin-api/src/routing/useRouteRef'; +import { convertLegacyRouteRef } from '../convertLegacyRouteRef'; + +class CompatComponentsApi implements ComponentsApi { + readonly #Progress: ComponentType; + readonly #NotFoundErrorPage: ComponentType; + readonly #ErrorBoundaryFallback: ComponentType; + + constructor(app: AppContext) { + const components = app.getComponents(); + const ErrorBoundaryFallback = (props: CoreErrorBoundaryFallbackProps) => ( + + ); + this.#Progress = components.Progress; + this.#NotFoundErrorPage = components.NotFoundErrorPage; + this.#ErrorBoundaryFallback = ErrorBoundaryFallback; + } + + getComponent(ref: ComponentRef): ComponentType { + switch (ref.id) { + case coreComponentRefs.progress.id: + return this.#Progress as ComponentType; + case coreComponentRefs.notFoundErrorPage.id: + return this.#NotFoundErrorPage as ComponentType; + case coreComponentRefs.errorBoundaryFallback.id: + return this.#ErrorBoundaryFallback as ComponentType; + default: + throw new Error( + `No backwards compatible component is available for ref '${ref.id}'`, + ); + } + } +} + +class CompatIconsApi implements IconsApi { + readonly #app: AppContext; + + constructor(app: AppContext) { + this.#app = app; + } + + getIcon(key: string): IconComponent | undefined { + return this.#app.getSystemIcon(key); + } + + listIconKeys(): string[] { + return Object.keys(this.#app.getSystemIcons()); + } +} + +class CompatRouteResolutionApi implements RouteResolutionApi { + readonly #routeResolver: RouteResolver; + + constructor(routeResolver: RouteResolver) { + this.#routeResolver = routeResolver; + } + + resolve( + anyRouteRef: + | RouteRef + | SubRouteRef + | ExternalRouteRef, + options?: RouteResolutionApiResolveOptions | undefined, + ): RouteFunc | undefined { + const legacyRef = convertLegacyRouteRef(anyRouteRef as RouteRef); + return this.#routeResolver.resolve(legacyRef, options?.sourcePath ?? '/'); + } +} + +class ForwardsCompatApis implements ApiHolder { + readonly #componentsApi: ComponentsApi; + readonly #iconsApi: IconsApi; + readonly #routeResolutionApi: RouteResolutionApi; + + constructor(app: AppContext, routeResolver: RouteResolver) { + this.#componentsApi = new CompatComponentsApi(app); + this.#iconsApi = new CompatIconsApi(app); + this.#routeResolutionApi = new CompatRouteResolutionApi(routeResolver); + } + + get(ref: ApiRef): T | undefined { + if (ref.id === componentsApiRef.id) { + return this.#componentsApi as T; + } else if (ref.id === iconsApiRef.id) { + return this.#iconsApi as T; + } else if (ref.id === routeResolutionApiRef.id) { + return this.#routeResolutionApi as T; + } + return undefined; + } +} + +function NewAppApisProvider(props: { children: ReactNode }) { + const app = useApp(); + const versionedRouteResolverContext = useVersionedContext<{ + 1: RouteResolver; + }>('routing-context'); + if (!versionedRouteResolverContext) { + throw new Error('Routing context is not available'); + } + const routeResolver = versionedRouteResolverContext.atVersion(1); + if (!routeResolver) { + throw new Error('RoutingContext v1 not available'); + } + + const appFallbackApis = useMemo( + () => new ForwardsCompatApis(app, routeResolver), + [app, routeResolver], + ); + + return {props.children}; +} export function ForwardsCompatProvider(props: { children: ReactNode }) { - // TODO(Rugvip): Implement - return <>{props.children}; + return {props.children}; } diff --git a/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx b/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx index 74b9f209eb..04e2361087 100644 --- a/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx +++ b/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx @@ -16,21 +16,28 @@ import React from 'react'; import { + componentsApiRef, + coreComponentRefs, coreExtensionData, createExtension, + iconsApiRef, + useRouteRef as useNewRouteRef, + createRouteRef as createNewRouteRef, + useApi, } from '@backstage/frontend-plugin-api'; import { createExtensionTester, - renderInTestApp, + renderInTestApp as renderInNewTestApp, } from '@backstage/frontend-test-utils'; import { screen } from '@testing-library/react'; import { compatWrapper } from './compatWrapper'; import { - createRouteRef, useApp, - useRouteRef, + useRouteRef as useOldRouteRef, + createRouteRef as createOldRouteRef, } from '@backstage/core-plugin-api'; import { convertLegacyRouteRef } from '../convertLegacyRouteRef'; +import { renderInTestApp as renderInOldTestApp } from '@backstage/test-utils'; describe('BackwardsCompatProvider', () => { it('should convert the app context', () => { @@ -74,14 +81,58 @@ describe('BackwardsCompatProvider', () => { }); it('should convert the routing context', () => { - const routeRef = createRouteRef({ id: 'test' }); + const routeRef = createOldRouteRef({ id: 'test' }); function Component() { - const link = useRouteRef(routeRef); + const link = useOldRouteRef(routeRef); return
link: {link()}
; } - renderInTestApp(compatWrapper(), { + renderInNewTestApp(compatWrapper(), { + mountedRoutes: { '/test': convertLegacyRouteRef(routeRef) }, + }); + + expect(screen.getByText('link: /test')).toBeInTheDocument(); + }); +}); + +describe('ForwardsCompatProvider', () => { + it('should convert the app context', async () => { + function Component() { + const components = useApi(componentsApiRef); + const icons = useApi(iconsApiRef); + return ( +
+ components:{' '} + {Object.entries(coreComponentRefs) + .map( + ([name, ref]) => + `${name}=${Boolean(components.getComponent(ref))}`, + ) + .join(', ')} + {'\n'} + icons: {icons.listIconKeys().join(', ')} +
+ ); + } + + await renderInOldTestApp(compatWrapper()); + + expect(screen.getByTestId('ctx').textContent).toMatchInlineSnapshot(` + "components: progress=true, notFoundErrorPage=true, errorBoundaryFallback=true + icons: kind:api, kind:component, kind:domain, kind:group, kind:location, kind:system, kind:user, kind:resource, kind:template, brokenImage, catalog, scaffolder, techdocs, search, chat, dashboard, docs, email, github, group, help, user, warning" + `); + }); + + it('should convert the routing context', async () => { + const routeRef = createNewRouteRef(); + + function Component() { + const link = useNewRouteRef(routeRef); + return
link: {link?.()}
; + } + + await renderInOldTestApp(compatWrapper(), { mountedRoutes: { '/test': convertLegacyRouteRef(routeRef) }, }); diff --git a/packages/core-compat-api/src/convertLegacyRouteRef.test.ts b/packages/core-compat-api/src/convertLegacyRouteRef.test.ts new file mode 100644 index 0000000000..f09060212c --- /dev/null +++ b/packages/core-compat-api/src/convertLegacyRouteRef.test.ts @@ -0,0 +1,203 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + RouteRef as OldRouteRef, + SubRouteRef as OldSubRouteRef, + ExternalRouteRef as OldExternalRouteRef, + createRouteRef as createOldRouteRef, + createSubRouteRef as createOldSubRouteRef, + createExternalRouteRef as createOldExternalRouteRef, +} from '@backstage/core-plugin-api'; +import { + RouteRef as NewRouteRef, + SubRouteRef as NewSubRouteRef, + ExternalRouteRef as NewExternalRouteRef, + createRouteRef as createNewRouteRef, + createSubRouteRef as createNewSubRouteRef, + createExternalRouteRef as createNewExternalRouteRef, +} from '@backstage/frontend-plugin-api'; +import { convertLegacyRouteRef } from './convertLegacyRouteRef'; + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalRouteRef as toInternalNewRouteRef } from '../../frontend-plugin-api/src/routing/RouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalSubRouteRef as toInternalNewSubRouteRef } from '../../frontend-plugin-api/src/routing/SubRouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExternalRouteRef as toInternalNewExternalRouteRef } from '../../frontend-plugin-api/src/routing/ExternalRouteRef'; + +describe('convertLegacyRouteRef', () => { + it('converts old to new', () => { + const ref1 = createOldRouteRef({ id: 'ref1' }); + const ref2 = createOldRouteRef({ id: 'ref2', params: ['p1', 'p2'] }); + const ref1sub1 = createOldSubRouteRef({ + id: 'sub1', + parent: ref1, + path: '/sub1', + }); + const ref1sub2 = createOldSubRouteRef({ + id: 'sub2', + parent: ref1, + path: '/sub2/:p3', + }); + const ref2sub1 = createOldSubRouteRef({ + id: 'sub1', + parent: ref2, + path: '/sub1/:p3', + }); + const ref3 = createOldExternalRouteRef({ + id: 'ref3', + }); + const ref4 = createOldExternalRouteRef({ + id: 'ref4', + optional: true, + defaultTarget: 'ref2', + params: ['p1', 'p2'], + }); + + const ref1Converted: NewRouteRef = convertLegacyRouteRef(ref1); + const ref2Converted: NewRouteRef = convertLegacyRouteRef(ref2); + const ref1sub1Converted: NewSubRouteRef = convertLegacyRouteRef(ref1sub1); + const ref1sub2Converted: NewSubRouteRef = convertLegacyRouteRef(ref1sub2); + const ref2sub1Converted: NewSubRouteRef = convertLegacyRouteRef(ref2sub1); + const ref3Converted: NewExternalRouteRef = convertLegacyRouteRef(ref3); + const ref4Converted: NewExternalRouteRef = convertLegacyRouteRef(ref4); + + // Check for reference equality + expect(ref1).toBe(ref1Converted); + expect(ref2).toBe(ref2Converted); + expect(ref1sub1).toBe(ref1sub1Converted); + expect(ref1sub2).toBe(ref1sub2Converted); + expect(ref2sub1).toBe(ref2sub1Converted); + expect(ref3).toBe(ref3Converted); + expect(ref4).toBe(ref4Converted); + + const ref1Internal = toInternalNewRouteRef(ref1Converted); + const ref2Internal = toInternalNewRouteRef(ref2Converted); + const ref1sub1Internal = toInternalNewSubRouteRef(ref1sub1Converted); + const ref1sub2Internal = toInternalNewSubRouteRef(ref1sub2Converted); + const ref2sub1Internal = toInternalNewSubRouteRef(ref2sub1Converted); + const ref3Internal = toInternalNewExternalRouteRef(ref3Converted); + const ref4Internal = toInternalNewExternalRouteRef(ref4Converted); + + expect(ref1Internal.getDescription()).toBe( + 'routeRef{type=absolute,id=ref1}', + ); + expect(ref1Internal.getParams()).toEqual([]); + expect(ref2Internal.getDescription()).toBe( + 'routeRef{type=absolute,id=ref2}', + ); + expect(ref2Internal.getParams()).toEqual(['p1', 'p2']); + + expect(ref1sub1Internal.getDescription()).toBe( + 'routeRef{type=sub,id=sub1}', + ); + expect(ref1sub1Internal.getParams()).toEqual([]); + expect(ref1sub1Internal.getParent()).toBe(ref1); + expect(ref1sub2Internal.getDescription()).toBe( + 'routeRef{type=sub,id=sub2}', + ); + expect(ref1sub2Internal.getParams()).toEqual(['p3']); + expect(ref1sub2Internal.getParent()).toBe(ref1); + expect(ref2sub1Internal.getDescription()).toBe( + 'routeRef{type=sub,id=sub1}', + ); + expect(ref2sub1Internal.getParams()).toEqual(['p1', 'p2', 'p3']); + expect(ref2sub1Internal.getParent()).toBe(ref2); + + expect(ref3Internal.getDefaultTarget()).toBe(undefined); + expect(ref3Internal.getDescription()).toBe( + 'routeRef{type=external,id=ref3}', + ); + expect(ref3Internal.getParams()).toEqual([]); + expect(ref4Internal.getDefaultTarget()).toBe('ref2'); + expect(ref4Internal.getDescription()).toBe( + 'routeRef{type=external,id=ref4}', + ); + expect(ref4Internal.getParams()).toEqual(['p1', 'p2']); + }); + + it('converts new to old', () => { + const ref1 = createNewRouteRef(); + const ref2 = createNewRouteRef({ params: ['p1', 'p2'] }); + const ref1sub1 = createNewSubRouteRef({ + parent: ref1, + path: '/sub1', + }); + const ref1sub2 = createNewSubRouteRef({ + parent: ref1, + path: '/sub2/:p3', + }); + const ref2sub1 = createNewSubRouteRef({ + parent: ref2, + path: '/sub1/:p3', + }); + const ref3 = createNewExternalRouteRef(); + const ref4 = createNewExternalRouteRef({ + defaultTarget: 'ref2', + params: ['p1', 'p2'], + }); + + const ref1Converted: OldRouteRef = convertLegacyRouteRef(ref1); + const ref2Converted: OldRouteRef = convertLegacyRouteRef(ref2); + const ref1sub1Converted: OldSubRouteRef = convertLegacyRouteRef(ref1sub1); + const ref1sub2Converted: OldSubRouteRef = convertLegacyRouteRef(ref1sub2); + const ref2sub1Converted: OldSubRouteRef = convertLegacyRouteRef(ref2sub1); + const ref3Converted: OldExternalRouteRef = convertLegacyRouteRef(ref3); + const ref4Converted: OldExternalRouteRef = convertLegacyRouteRef(ref4); + + // Check for reference equality + expect(ref1).toBe(ref1Converted); + expect(ref2).toBe(ref2Converted); + expect(ref1sub1).toBe(ref1sub1Converted); + expect(ref1sub2).toBe(ref1sub2Converted); + expect(ref2sub1).toBe(ref2sub1Converted); + expect(ref3).toBe(ref3Converted); + expect(ref4).toBe(ref4Converted); + + expect(String(ref1Converted)).toMatch(/^RouteRef\{created at '.*'\}$/); + expect(ref1Converted.params).toEqual([]); + expect(String(ref2Converted)).toMatch(/^RouteRef\{created at '.*'\}$/); + expect(ref2Converted.params).toEqual(['p1', 'p2']); + + expect(String(ref1sub1Converted)).toMatch( + /^SubRouteRef\{at \/sub1 with parent created at '.*'\}$/, + ); + expect(ref1sub1Converted.params).toEqual([]); + expect(ref1sub1Converted.parent).toBe(ref1); + expect(String(ref1sub2Converted)).toMatch( + /^SubRouteRef\{at \/sub2\/:p3 with parent created at '.*'\}$/, + ); + expect(ref1sub2Converted.params).toEqual(['p3']); + expect(ref1sub2Converted.parent).toBe(ref1); + expect(String(ref2sub1Converted)).toMatch( + /^SubRouteRef\{at \/sub1\/:p3 with parent created at '.*'\}$/, + ); + expect(ref2sub1Converted.params).toEqual(['p1', 'p2', 'p3']); + expect(ref2sub1Converted.parent).toBe(ref2); + + expect(String(ref3Converted)).toMatch( + /^ExternalRouteRef\{created at '.*'\}$/, + ); + expect(ref3Converted.params).toEqual([]); + expect(ref3Converted.optional).toBe(true); + expect(String(ref4Converted)).toMatch( + /^ExternalRouteRef\{created at '.*'\}$/, + ); + expect(ref4Converted.params).toEqual(['p1', 'p2']); + expect(ref4Converted.optional).toBe(true); + }); +}); diff --git a/packages/core-compat-api/src/convertLegacyRouteRef.ts b/packages/core-compat-api/src/convertLegacyRouteRef.ts index c967f9e9b5..40a95a81ff 100644 --- a/packages/core-compat-api/src/convertLegacyRouteRef.ts +++ b/packages/core-compat-api/src/convertLegacyRouteRef.ts @@ -51,8 +51,8 @@ export type ToNewRouteRef< ? RouteRef : T extends LegacySubRouteRef ? SubRouteRef - : T extends LegacyExternalRouteRef - ? ExternalRouteRef + : T extends LegacyExternalRouteRef + ? ExternalRouteRef : never; /** @@ -109,23 +109,115 @@ export function convertLegacyRouteRef( * * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems. */ -export function convertLegacyRouteRef< - TParams extends AnyRouteRefParams, - TOptional extends boolean, ->( - ref: LegacyExternalRouteRef, -): ExternalRouteRef; +export function convertLegacyRouteRef( + ref: LegacyExternalRouteRef, +): ExternalRouteRef; +/** + * A temporary helper to convert a new route ref to the legacy system. + * + * @public + * @remarks + * + * In the future the legacy createRouteRef will instead create refs compatible with both systems. + */ +export function convertLegacyRouteRef( + ref: RouteRef, +): LegacyRouteRef; + +/** + * A temporary helper to convert a new sub route ref to the legacy system. + * + * @public + * @remarks + * + * In the future the legacy createSubRouteRef will instead create refs compatible with both systems. + */ +export function convertLegacyRouteRef( + ref: SubRouteRef, +): LegacySubRouteRef; + +/** + * A temporary helper to convert a new external route ref to the legacy system. + * + * @public + * @remarks + * + * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems. + */ +export function convertLegacyRouteRef( + ref: ExternalRouteRef, +): LegacyExternalRouteRef; export function convertLegacyRouteRef( - ref: LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef, -): RouteRef | SubRouteRef | ExternalRouteRef { + ref: + | LegacyRouteRef + | LegacySubRouteRef + | LegacyExternalRouteRef + | RouteRef + | SubRouteRef + | ExternalRouteRef, +): + | RouteRef + | SubRouteRef + | ExternalRouteRef + | LegacyRouteRef + | LegacySubRouteRef + | LegacyExternalRouteRef { + const isNew = '$$type' in ref; + const oldType = (ref as unknown as { [routeRefType]: unknown })[routeRefType]; + // Ref has already been converted - if ('$$type' in ref) { - return ref as unknown as RouteRef | SubRouteRef | ExternalRouteRef; + if (isNew && oldType) { + return ref as any; } - const type = (ref as unknown as { [routeRefType]: unknown })[routeRefType]; + if (isNew) { + return convertNewToOld( + ref as unknown as RouteRef | SubRouteRef | ExternalRouteRef, + ); + } + return convertOldToNew(ref, oldType); +} + +function convertNewToOld( + ref: RouteRef | SubRouteRef | ExternalRouteRef, +): LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef { + if (ref.$$type === '@backstage/RouteRef') { + const newRef = toInternalRouteRef(ref); + return Object.assign(ref, { + [routeRefType]: 'absolute', + params: newRef.getParams(), + title: newRef.getDescription(), + } as Omit) as unknown as LegacyRouteRef; + } + if (ref.$$type === '@backstage/SubRouteRef') { + const newRef = toInternalSubRouteRef(ref); + return Object.assign(ref, { + [routeRefType]: 'sub', + parent: convertLegacyRouteRef(newRef.getParent()), + params: newRef.getParams(), + } as Omit) as unknown as LegacySubRouteRef; + } + if (ref.$$type === '@backstage/ExternalRouteRef') { + const newRef = toInternalExternalRouteRef(ref); + return Object.assign(ref, { + [routeRefType]: 'external', + optional: true, + params: newRef.getParams(), + defaultTarget: newRef.getDefaultTarget(), + } as Omit) as unknown as LegacyExternalRouteRef; + } + + throw new Error( + `Failed to convert route ref, unknown type '${(ref as any).$$type}'`, + ); +} + +function convertOldToNew( + ref: LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef, + type: unknown, +): RouteRef | SubRouteRef | ExternalRouteRef { if (type === 'absolute') { const legacyRef = ref as LegacyRouteRef; const legacyRefStr = String(legacyRef); @@ -185,7 +277,6 @@ export function convertLegacyRouteRef( const newRef = toInternalExternalRouteRef( createExternalRouteRef<{ [key in string]: string }>({ params: legacyRef.params as string[], - optional: legacyRef.optional, defaultTarget: 'getDefaultTarget' in legacyRef ? (legacyRef.getDefaultTarget as () => string | undefined)() @@ -196,7 +287,6 @@ export function convertLegacyRouteRef( $$type: '@backstage/ExternalRouteRef' as const, version: 'v1', T: newRef.T, - optional: newRef.optional, getParams() { return newRef.getParams(); }, diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 163406bbca..a2463f594e 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/core-components +## 0.14.10-next.0 + +### Patch Changes + +- 678971a: Move the `Link` component to the `RoutedTabs` instead of the `HeaderTabs` component +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + +## 0.14.9 + +### Patch Changes + +- d4ffdbb: Fixed bug where ` diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 73060ebd4a..30e2e77a6e 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.2.22-next.1 + +### Patch Changes + +- 3fca643: Added method `listBranchesByRepository` to `BitbucketCloudClient` +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + +## 0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + +## 0.2.21 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/integration@1.13.0 + ## 0.2.21-next.0 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/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/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index 0e98fcc505..d2f22cc966 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", - "version": "0.2.21-next.0", + "version": "0.2.22-next.1", "description": "Common functionalities for bitbucket-cloud plugins", "backstage": { "role": "common-library", 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'); + }); }); 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 diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 15f944de19..69c16e9875 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,76 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.3.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.3.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.3.18-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- 90a7340: `AwsOrganizationCloudAccountProcessor` configuration field `roleArn` is deprecated in favor of new field `accountId` +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + +## 0.3.17 + +### Patch Changes + +- 4afa050: Export `defaultEksClusterEntityTransformer` to allow library consumers to layer additional changes on top of the default transformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + ## 0.3.17-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/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/package.json b/plugins/catalog-backend-module-aws/package.json index 7081b09d2b..443dfebb87 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", - "version": "0.3.17-next.1", + "version": "0.3.18-next.2", "description": "A Backstage catalog backend module that helps integrate towards AWS", "backstage": { "role": "backend-plugin-module", 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..ea16394e0a 100644 --- a/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts +++ b/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts @@ -22,8 +22,14 @@ import { Config } from '@backstage/config'; export type AwsOrganizationProviderConfig = { /** * The role to assume for the processor. + * @deprecated Use `accountId` instead. */ roleArn?: string; + + /** + * The AWS accountId + */ + accountId?: string; }; export function readAwsOrganizationConfig( @@ -32,7 +38,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/AwsEKSClusterProcessor.ts b/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts index a491dbab7d..a5f5ce2f6c 100644 --- a/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts +++ b/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts @@ -106,6 +106,7 @@ export class AwsEKSClusterProcessor implements CatalogProcessor { } const eksClient = new EKS({ + customUserAgent: 'backstage-aws-catalog-eks-cluster-processor', credentials, credentialDefaultProvider: providerFunction, region, diff --git a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts index 4a454fce6f..73d7a63e2b 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, diff --git a/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts b/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts index 91ba76b695..0c58fe3f3a 100644 --- a/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts +++ b/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts @@ -154,6 +154,7 @@ export class AwsS3EntityProvider implements EntityProvider { accountId ? { accountId } : undefined, ); this.s3 = new S3({ + customUserAgent: 'backstage-aws-catalog-s3-entity-provider', apiVersion: '2006-03-01', credentialDefaultProvider: () => credProvider.sdkCredentialProvider, endpoint: this.integration.config.endpoint, diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 1f672302ac..89d6847511 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.43-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + +## 0.1.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + +## 0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + +## 0.1.42 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/config@1.2.0 + ## 0.1.42-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 1159aff6db..de18ae5895 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", - "version": "0.1.42-next.1", + "version": "0.1.43-next.2", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", @@ -58,7 +58,7 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts index ef00610dc0..4839b625d2 100644 --- a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts +++ b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { codeSearch, CodeSearchResponse } from './azure'; @@ -26,7 +26,7 @@ import { ConfigReader } from '@backstage/config'; describe('azure', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); const createFixture = (host: string, token: string) => { const azureConfig = { diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index 125778b4b6..771702d86d 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/backend-openapi-utils@0.1.16-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-openapi-utils@0.1.16-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-tasks@0.5.27 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.5-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index fad1dc47c9..d9ba70c806 100644 --- a/plugins/catalog-backend-module-backstage-openapi/package.json +++ b/plugins/catalog-backend-module-backstage-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-backstage-openapi", - "version": "0.2.5-next.1", + "version": "0.2.6-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 4ad56f2aa3..ec27de045c 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,73 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.1 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index e691c2a3c3..3f4389788c 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", - "version": "0.2.9-next.1", + "version": "0.2.10-next.2", "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-cloud/src/providers/BitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts index 55b701e016..80d09f3e2f 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts @@ -22,7 +22,7 @@ import { } from '@backstage/backend-tasks'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { CatalogApi } from '@backstage/catalog-client'; import { Entity, LocationEntity } from '@backstage/catalog-model'; @@ -62,7 +62,7 @@ const logger = mockServices.logger.mock(); const server = setupServer(); describe('BitbucketCloudEntityProvider', () => { - setupRequestMockHandlers(server); + registerMswTestHooks(server); const simpleConfig = new ConfigReader({ catalog: { diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index a5901702ff..46469b747a 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.37-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.36 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.36-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 4e47fcbdcc..eeafae91d5 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.1.36-next.1", + "version": "0.1.37-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", @@ -59,7 +59,7 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@types/node-fetch": "^2.5.12", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts index a3d4155121..db2a05d0b1 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { BitbucketServerIntegrationConfig } from '@backstage/integration'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -50,7 +50,7 @@ describe('BitbucketServerClient', () => { config: config, }); - setupRequestMockHandlers(server); + registerMswTestHooks(server); it('listProjects', async () => { server.use( diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts index 9624e396cd..49b69f0fa6 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/backend-tasks'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; @@ -103,7 +103,7 @@ function setupStubs(projects: Project[], baseUrl: string) { } describe('BitbucketServerEntityProvider', () => { - setupRequestMockHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.clearAllMocks(); }); diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index b76bc9d7a9..f5f805edd9 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-kubernetes-common@0.8.1 + +## 0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.1.23-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 0888a9eb03..0673dd1805 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", - "version": "0.1.23-next.1", + "version": "0.1.24-next.2", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 6492e65ffa..d4b173cc3f 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.40-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.39-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index b99347e6f5..b10e48d34b 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.1.39-next.1", + "version": "0.1.40-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", @@ -55,7 +55,7 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts index 8b1acbdbaa..ee3555c7f9 100644 --- a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/backend-tasks'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; @@ -57,7 +57,7 @@ class PersistingTaskRunner implements TaskRunner { const logger = mockServices.logger.mock(); describe('GerritEntityProvider', () => { - setupRequestMockHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.clearAllMocks(); diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 0236b1d30c..ebaa50af30 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend-module-github@0.6.5 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + ## 0.1.17-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index abd92889a0..e1f60aec67 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", - "version": "0.1.17-next.1", + "version": "0.1.18-next.2", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 02975d2b68..c7a032c43e 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,101 @@ # @backstage/plugin-catalog-backend-module-github +## 0.6.6-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.6.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.6.5 + +### Patch Changes + +- 9112efc: Adds support for `repository` events. + + The provider adds a subscription to the topic `github.repository`. + + Hereby, it supports events of type `repository` with actions + + - `archived` + - `deleted` + - `edited` + - `renamed` + - `transferred` + - `unarchived` + + Actions skipped as they don't require entity changes: + + - `created` + - `privatized` + - `publicized` + + If the config option `validateLocationsExist` is enabled, an API request + is necessary and will be executed. + This affects the actions `renamed`, `transferred`, and `unarchive` + of event type `repository`. + + Catalog entities related to the `GithubEntityProvider` instance will be adjusted + according to action and its meaning for them. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.6.5-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index c8b78c5e92..dfde8e9718 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github", - "version": "0.6.5-next.1", + "version": "0.6.6-next.2", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", @@ -67,7 +67,7 @@ "git-url-parse": "^14.0.0", "lodash": "^4.17.21", "minimatch": "^9.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts index e5c7eb5896..29c8cbc66d 100644 --- a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts +++ b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts @@ -35,7 +35,7 @@ jest.mock('@octokit/rest', () => { import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { GithubLocationAnalyzer } from './GithubLocationAnalyzer'; import { - setupRequestMockHandlers, + registerMswTestHooks, mockServices, } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; @@ -63,7 +63,7 @@ describe('GithubLocationAnalyzer', () => { }, }); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { server.use( diff --git a/plugins/catalog-backend-module-github/src/lib/github.test.ts b/plugins/catalog-backend-module-github/src/lib/github.test.ts index d83e8031cc..9eae9e1161 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { graphql as graphqlOctokit } from '@octokit/graphql'; import { graphql as graphqlMsw } from 'msw'; @@ -39,7 +39,7 @@ describe('github', () => { const graphql = graphqlOctokit.defaults({ request: { fetch } }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); describe('getOrganizationUsers using defaultUserMapper', () => { it('reads members', async () => { diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index d86cb76c24..5611260f87 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## 0.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.21 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + ## 0.0.5-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index a08a42d1f3..68e1c8f252 100644 --- a/plugins/catalog-backend-module-gitlab-org/package.json +++ b/plugins/catalog-backend-module-gitlab-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab-org", - "version": "0.0.5-next.1", + "version": "0.0.6-next.2", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 8d6eb4bfef..737f79de59 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,68 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.22-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.3.22-next.1 + +### Patch Changes + +- c7b14ed: Adds new optional `excludeRepos` configuration option to the Gitlab catalog provider. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.3.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.3.21 + +### Patch Changes + +- 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.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.3.21-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/api-report.md b/plugins/catalog-backend-module-gitlab/api-report.md index 2b78c67205..0a1e4b7d36 100644 --- a/plugins/catalog-backend-module-gitlab/api-report.md +++ b/plugins/catalog-backend-module-gitlab/api-report.md @@ -110,6 +110,7 @@ export type GitlabProviderConfig = { orgEnabled?: boolean; schedule?: TaskScheduleDefinition; skipForkedRepos?: boolean; + excludeRepos?: string[]; }; // @public diff --git a/plugins/catalog-backend-module-gitlab/config.d.ts b/plugins/catalog-backend-module-gitlab/config.d.ts index 7d183b6e58..9f009ee478 100644 --- a/plugins/catalog-backend-module-gitlab/config.d.ts +++ b/plugins/catalog-backend-module-gitlab/config.d.ts @@ -63,6 +63,11 @@ export interface Config { * (Optional) Skip forked repository */ skipForkedRepos?: boolean; + /** + * (Optional) A list of strings containing the paths of the repositories to skip + * Should be in the format group/subgroup/repo, with no leading or trailing slashes. + */ + excludeRepos?: string[]; }; }; }; diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 0780ccdd6a..d15deafd08 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", - "version": "0.3.21-next.1", + "version": "0.3.22-next.2", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", @@ -62,7 +62,7 @@ "@backstage/plugin-events-node": "workspace:^", "@gitbeaker/rest": "^40.0.3", "lodash": "^4.17.21", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts index c1608cd386..d7ce338d6d 100644 --- a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts @@ -16,7 +16,7 @@ import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { LocationSpec } from '@backstage/plugin-catalog-node'; @@ -157,7 +157,7 @@ function getProcessor({ } describe('GitlabDiscoveryProcessor', () => { - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeAll(() => { jest.useFakeTimers(); diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts index 798df32695..4a173c6b50 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts @@ -299,6 +299,33 @@ export const config_single_integration_skip_forks: MockObject = { }, }; +export const config_single_integration_exclude_repos: MockObject = { + integrations: { + gitlab: [ + { + host: 'example.com', + apiBaseUrl: 'https://example.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'example.com', + group: 'group1', + excludeRepos: ['group1/test-repo1'], + schedule: { + frequency: 'PT30M', + timeout: 'PT3M', + }, + }, + }, + }, + }, +}; + export const config_no_schedule: MockObject = { integrations: { gitlab: [ diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts index 7d40eb1204..1eebe7d6e0 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts @@ -16,7 +16,7 @@ import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { readGitLabIntegrationConfig } from '@backstage/integration'; @@ -27,7 +27,7 @@ import { GitLabClient, paginated } from './client'; import { GitLabGroup, GitLabUser } from './types'; const server = setupServer(...handlers); -setupRequestMockHandlers(server); +registerMswTestHooks(server); describe('GitLabClient', () => { describe('isSelfManaged', () => { diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 0b9ea6a868..69c8ed5f92 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -201,6 +201,11 @@ export type GitlabProviderConfig = { * If the project is a fork, skip repository */ skipForkedRepos?: boolean; + /** + * List of repositories to exclude from discovery, should be the full path to the repository, e.g. `group/project` + * Paths should not start or end with a slash. + */ + excludeRepos?: string[]; }; /** diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts index e89b378cfe..f5e167e564 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/backend-tasks'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; @@ -32,7 +32,7 @@ import * as mock from '../__testUtils__/mocks'; import { GitlabDiscoveryEntityProvider } from './GitlabDiscoveryEntityProvider'; const server = setupServer(...handlers); -setupRequestMockHandlers(server); +registerMswTestHooks(server); afterEach(() => jest.clearAllMocks()); class PersistingTaskRunner implements TaskRunner { @@ -130,6 +130,7 @@ describe('GitlabDiscoveryEntityProvider - configuration', () => { ); }); }); + describe('GitlabDiscoveryEntityProvider - refresh', () => { it('should apply full update on scheduled execution', async () => { const config = new ConfigReader(mock.config_no_org_integration); @@ -231,6 +232,38 @@ describe('GitlabDiscoveryEntityProvider - refresh', () => { }); }); + it('should filter repositories that are excluded', async () => { + const config = new ConfigReader( + mock.config_single_integration_exclude_repos, + ); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + + await provider.connect(entityProviderConnection); + + await provider.refresh(logger); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_location_entities_default_branch.filter( + entity => + !entity.entity.metadata.annotations[ + 'backstage.io/managed-by-location' + ].includes('test-repo1') && + !entity.entity.metadata.annotations[ + 'backstage.io/managed-by-location' + ].includes('awesome'), + ), + }); + }); + // branch and fallback branch are undefined in the config it('should ingest catalog from project default branch only', async () => { const config = new ConfigReader(mock.config_single_integration); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts index b2ef475d9d..bbd90795be 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts @@ -470,6 +470,13 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { return false; } + if (this.config.excludeRepos?.includes(project.path_with_namespace ?? '')) { + this.logger.debug( + `Skipping project ${project.path_with_namespace} as it is excluded.`, + ); + return false; + } + const project_branch = this.config.branch ?? project.default_branch ?? diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts index ddc0d03570..9706384ff0 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/backend-tasks'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; @@ -33,7 +33,7 @@ import { GroupNameTransformerOptions } from '../lib/types'; import { GitlabOrgDiscoveryEntityProvider } from './GitlabOrgDiscoveryEntityProvider'; const server = setupServer(...handlers); -setupRequestMockHandlers(server); +registerMswTestHooks(server); afterEach(() => jest.clearAllMocks()); class PersistingTaskRunner implements TaskRunner { 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 4418dba50b..28df8c88b7 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts @@ -60,6 +60,7 @@ describe('config', () => { allowInherited: false, schedule: undefined, skipForkedRepos: false, + excludeRepos: [], restrictUsersToGroup: false, }), ); @@ -99,6 +100,7 @@ describe('config', () => { allowInherited: false, schedule: undefined, skipForkedRepos: false, + excludeRepos: [], restrictUsersToGroup: false, }), ); @@ -139,11 +141,54 @@ describe('config', () => { allowInherited: false, schedule: undefined, restrictUsersToGroup: false, + excludeRepos: [], skipForkedRepos: true, }), ); }); + it('valid config with excludeRepos', () => { + const config = new ConfigReader({ + catalog: { + providers: { + gitlab: { + test: { + group: 'group', + host: 'host', + branch: 'not-master', + fallbackBranch: 'main', + entityFilename: 'custom-file.yaml', + skipForkedRepos: false, + excludeRepos: ['foo/bar', 'quz/qux'], + }, + }, + }, + }, + }); + + const result = readGitlabConfigs(config); + expect(result).toHaveLength(1); + result.forEach(r => + expect(r).toStrictEqual({ + id: 'test', + group: 'group', + branch: 'not-master', + fallbackBranch: 'main', + host: 'host', + catalogFile: 'custom-file.yaml', + projectPattern: /[\s\S]*/, + groupPattern: /[\s\S]*/, + userPattern: /[\s\S]*/, + orgEnabled: false, + allowInherited: false, + schedule: undefined, + restrictUsersToGroup: false, + skipForkedRepos: false, + excludeRepos: ['foo/bar', 'quz/qux'], + }), + ); + }); + it('valid config with schedule', () => { const config = new ConfigReader({ catalog: { @@ -181,6 +226,7 @@ describe('config', () => { allowInherited: false, skipForkedRepos: false, restrictUsersToGroup: false, + excludeRepos: [], schedule: { frequency: { minutes: 30 }, timeout: { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index 68eba7165a..d26cba5328 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -47,6 +47,8 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { config.getOptionalBoolean('allowInherited') ?? false; const skipForkedRepos: boolean = config.getOptionalBoolean('skipForkedRepos') ?? false; + const excludeRepos: string[] = + config.getOptionalStringArray('excludeRepos') ?? []; const schedule = config.has('schedule') ? readTaskScheduleDefinitionFromConfig(config.getConfig('schedule')) @@ -68,6 +70,7 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { orgEnabled, allowInherited, skipForkedRepos, + excludeRepos, restrictUsersToGroup, }; } diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index 9cd19e259e..e56e14b95f 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.4.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.4.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## 0.4.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.4.27-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index c9cf1f5a82..f3744d9b07 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", - "version": "0.4.27-next.1", + "version": "0.4.28-next.2", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 6842b99282..8b8907bd7b 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,68 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + +## 0.7.0 + +### Minor Changes + +- cb32ca7: **BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items. + + Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.7.0-next.1 ### Minor Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 411f168fd8..fa627cb55f 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", - "version": "0.7.0-next.1", + "version": "0.7.1-next.2", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index c609fc369d..4637f19052 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## 0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.0.1 + +### Patch Changes + +- 97caf55: Creates a new module to make logging catalog errors simple. This module subscribes to catalog events and logs them. + + See [Backstage documentation](https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors) for details on how to install + and configure the plugin. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + ## 0.0.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index fe3f09c29c..a6609c7227 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "version": "0.0.1-next.1", + "version": "0.0.2-next.2", "description": "A module that subscribes to catalog releated events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index eb3591241f..2efe171ec1 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.31-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.5.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## 0.5.31-next.0 + +### Patch Changes + +- 58dff4d: Added option to ingest groups based on their group membership in Azure Entra ID +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + +## 0.5.30 + +### Patch Changes + +- f7bdcea: Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.5.30-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/api-report.md b/plugins/catalog-backend-module-msgraph/api-report.md index 9640f3708b..57f50fbd18 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 @@ -215,6 +215,7 @@ export type MicrosoftGraphProviderConfig = { groupFilter?: string; groupSearch?: string; groupSelect?: string[]; + groupIncludeSubGroups?: boolean; queryMode?: 'basic' | 'advanced'; loadUserPhotos?: boolean; schedule?: TaskScheduleDefinition; @@ -263,6 +264,7 @@ export function readMicrosoftGraphOrg( groupSearch?: string; groupFilter?: string; groupSelect?: string[]; + groupIncludeSubGroups?: boolean; queryMode?: 'basic' | 'advanced'; userTransformer?: UserTransformer; groupTransformer?: GroupTransformer; 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/package.json b/plugins/catalog-backend-module-msgraph/package.json index b04cd8788c..daba6c4b9f 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", - "version": "0.5.30-next.1", + "version": "0.5.31-next.2", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", @@ -62,7 +62,7 @@ "@microsoft/microsoft-graph-types": "^2.6.0", "@types/node-fetch": "^2.5.12", "lodash": "^4.17.21", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "p-limit": "^3.0.2", "qs": "^6.9.4", "uuid": "^9.0.0" diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts index 6d63537b54..624b6e42b0 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts @@ -15,7 +15,7 @@ */ import { TokenCredential } from '@azure/identity'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { MicrosoftGraphClient } from './client'; @@ -27,7 +27,7 @@ describe('MicrosoftGraphClient', () => { let client: MicrosoftGraphClient; const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { tokenCredential.getToken.mockResolvedValue({ 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. 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 c0e9f61f29..0ec56f134d 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts @@ -174,6 +174,7 @@ describe('readProviderConfigs', () => { expand: 'member', filter: 'securityEnabled eq false', select: ['id', 'displayName', 'description'], + includeSubGroups: true, }, schedule: { frequency: 'PT30M', @@ -202,6 +203,7 @@ describe('readProviderConfigs', () => { groupExpand: 'member', groupSelect: ['id', 'displayName', 'description'], groupFilter: 'securityEnabled eq false', + groupIncludeSubGroups: true, schedule: { frequency: { minutes: 30 }, 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 21995d2b8d..a019ac79a3 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts @@ -338,6 +338,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, diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index bf35045dcc..eb0dbcf08d 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,65 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.41-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-catalog-backend@1.24.1-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## 0.1.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## 0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + +## 0.1.40 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.1.40-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index b37cb09b15..aa4ec5a803 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", - "version": "0.1.40-next.1", + "version": "0.1.41-next.2", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index ead44a56aa..209160b4e1 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.1.29-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.1.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.1.28-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 114daa45e8..977379fefa 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", - "version": "0.1.28-next.1", + "version": "0.1.29-next.2", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", @@ -63,7 +63,7 @@ "@backstage/types": "workspace:^", "lodash": "^4.17.21", "luxon": "^3.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts b/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts index ac28f04503..8ad4c2b850 100644 --- a/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts +++ b/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts @@ -20,14 +20,14 @@ import { PuppetDbEntityProviderConfig, } from '../providers'; import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ANNOTATION_PUPPET_CERTNAME, ENDPOINT_FACTSETS } from './constants'; describe('readPuppetNodes', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 758d59c7c0..0813e4b6ab 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/catalog-model@1.5.0 + +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/catalog-model@1.5.0 + +## 0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + +## 0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + ## 0.1.20-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index 58bcdc6fb5..02c8a09ae9 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", - "version": "0.1.20-next.1", + "version": "0.1.21-next.2", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index afac0ebeed..37413e5f02 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.4.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.4-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## 0.4.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.4-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/plugin-permission-common@0.8.0 + +## 0.4.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + ## 0.4.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index c49a3d700d..eaf86d75ed 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", - "version": "0.4.9-next.1", + "version": "0.4.10-next.2", "description": "Backstage Catalog module to view unprocessed entities", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 65ed28cb6d..fe707b2a9a 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,100 @@ # @backstage/plugin-catalog-backend +## 1.24.1-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/backend-openapi-utils@0.1.16-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 1.24.1-next.1 + +### Patch Changes + +- 51240ee: Preserve default `allowedLocationTypes` when `setAllowedLocationTypes()` of `CatalogLocationsExtensionPoint` is not called. +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.1 + - @backstage/backend-openapi-utils@0.1.16-next.1 + - @backstage/backend-tasks@0.5.28-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-events-node@0.3.9-next.1 + +## 1.24.1-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + +## 1.24.0 + +### Minor Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.24.0-next.1 ### Minor Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index e554f0a334..0a046b43e4 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "1.24.0-next.1", + "version": "1.24.1-next.2", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", @@ -90,7 +90,7 @@ "lodash": "^4.17.21", "luxon": "^3.0.0", "minimatch": "^9.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "p-limit": "^3.0.2", "prom-client": "^15.0.0", "uuid": "^9.0.0", diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts index dd80f8f0c4..7d1578db00 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts @@ -17,7 +17,7 @@ import { UrlReader, UrlReaders } from '@backstage/backend-common'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { rest } from 'msw'; @@ -39,7 +39,7 @@ describe('UrlReaderProcessor', () => { set: jest.fn(), }; const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts index 4c1673b785..aee65bd2e1 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts @@ -18,7 +18,7 @@ import { PluginEndpointDiscovery, TokenManager, } from '@backstage/backend-common'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { Entity } from '@backstage/catalog-model'; import { DefaultCatalogCollator } from './DefaultCatalogCollator'; import { setupServer } from 'msw/node'; @@ -62,7 +62,7 @@ describe('DefaultCatalogCollator', () => { let mockTokenManager: jest.Mocked; let collator: DefaultCatalogCollator; - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeAll(() => { mockDiscoveryApi = { getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7007'), diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index aebd969701..269100e586 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: string[] | undefined; + + 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,12 @@ export const catalogPlugin = createBackendPlugin({ builder.addPermissionRules(...permissionExtensions.permissionRules); builder.setFieldFormatValidators(modelExtensions.fieldValidators); + if (locationTypeExtensions.allowedLocationTypes) { + builder.setAllowedLocationTypes( + locationTypeExtensions.allowedLocationTypes, + ); + } + const { processingEngine, router } = await builder.build(); lifecycle.addStartupHook(async () => { diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index fd3c714f97..2d0fde55da 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-common +## 1.0.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/catalog-model@1.5.0 + +## 1.0.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/catalog-model@1.5.0 + +## 1.0.25 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-model@1.5.0 + ## 1.0.24 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 0ea4ce5e3e..cfcfee74d8 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-common", - "version": "1.0.24", + "version": "1.0.26-next.1", "description": "Common functionalities for the catalog plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index f397955e1c..695af8d4fe 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,77 @@ # @backstage/plugin-catalog-graph +## 0.4.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## 0.4.8-next.2 + +### Patch Changes + +- 4a529c2: Use `entityPresentationApi` for the node title and the icon. +- Updated dependencies + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.12.3-next.1 + +## 0.4.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## 0.4.8-next.0 + +### Patch Changes + +- fba7537: Memoize entity graph nodes when applying an `entityFilter` to prevent repeated redraws +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + ## 0.4.7-next.2 ### Patch Changes diff --git a/plugins/catalog-graph/api-report-alpha.md b/plugins/catalog-graph/api-report-alpha.md index 3895f12fcf..88b3a38b76 100644 --- a/plugins/catalog-graph/api-report-alpha.md +++ b/plugins/catalog-graph/api-report-alpha.md @@ -13,14 +13,11 @@ const _default: BackstagePlugin< catalogGraph: RouteRef; }, { - catalogEntity: ExternalRouteRef< - { - name: string; - kind: string; - namespace: string; - }, - true - >; + catalogEntity: ExternalRouteRef<{ + name: string; + kind: string; + namespace: string; + }>; } >; export default _default; diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index eb27725d45..08a5497dc0 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.4.7-next.2", + "version": "0.4.8-next.3", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.test.tsx index 1f3d77e1ae..10aa62f946 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.test.tsx @@ -47,6 +47,7 @@ describe('', () => { ); expect(screen.getByText('kind:namespace/name')).toBeInTheDocument(); + expect(screen.getByText('namespace/name')).toBeInTheDocument(); }); test('renders node, skips default namespace', async () => { @@ -73,7 +74,7 @@ describe('', () => { , ); - expect(screen.getByText('kind:name')).toBeInTheDocument(); + expect(screen.getByText('name')).toBeInTheDocument(); }); test('renders node with onClick', async () => { @@ -102,8 +103,8 @@ describe('', () => { , ); - expect(screen.getByText('kind:namespace/name')).toBeInTheDocument(); - await userEvent.click(screen.getByText('kind:namespace/name')); + expect(screen.getByText('namespace/name')).toBeInTheDocument(); + await userEvent.click(screen.getByText('namespace/name')); expect(onClick).toHaveBeenCalledTimes(1); }); @@ -134,5 +135,6 @@ describe('', () => { ); expect(screen.getByText('Custom Title')).toBeInTheDocument(); + expect(screen.getByText('kind:namespace/name')).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.tsx index d55f4c015b..bc3311d33f 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderNode.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ import { DependencyGraphTypes } from '@backstage/core-components'; -import { useApp } from '@backstage/core-plugin-api'; -import { humanizeEntityRef } from '@backstage/plugin-catalog-react'; +import { IconComponent } from '@backstage/core-plugin-api'; +import { useEntityPresentation } from '@backstage/plugin-catalog-react'; import { makeStyles } from '@material-ui/core/styles'; import classNames from 'classnames'; import React, { useLayoutEffect, useRef, useState } from 'react'; -import { EntityKindIcon } from './EntityKindIcon'; +import { EntityIcon } from './EntityIcon'; import { EntityNodeData } from './types'; import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; @@ -64,8 +64,10 @@ export function DefaultRenderNode({ const classes = useStyles(); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); - const app = useApp(); const idRef = useRef(null); + const entityRefPresentationSnapshot = useEntityPresentation(entity, { + defaultNamespace: DEFAULT_NAMESPACE, + }); useLayoutEffect(() => { // set the width to the length of the ID @@ -82,25 +84,14 @@ export function DefaultRenderNode({ } }, [width, height]); - const { - kind, - metadata: { name, namespace = DEFAULT_NAMESPACE, title }, - } = entity; - - const hasKindIcon = app.getSystemIcon( - `kind:${kind.toLocaleLowerCase('en-US')}`, - ); + const hasKindIcon = !!entityRefPresentationSnapshot.Icon; const padding = 10; const iconSize = height; const paddedIconWidth = hasKindIcon ? iconSize + padding : 0; const paddedWidth = paddedIconWidth + width + padding * 2; const paddedHeight = height + padding * 2; - const displayTitle = - title ?? - (kind && name && namespace - ? humanizeEntityRef({ kind, name, namespace }) - : id); + const displayTitle = entityRefPresentationSnapshot.primaryTitle ?? id; return ( @@ -115,8 +106,8 @@ export function DefaultRenderNode({ rx={10} /> {hasKindIcon && ( - {displayTitle} + {entityRefPresentationSnapshot.entityRef} ); } diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityIcon.test.tsx similarity index 81% rename from plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.test.tsx rename to plugins/catalog-graph/src/components/EntityRelationsGraph/EntityIcon.test.tsx index cc47c8850b..8683af9c1e 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityIcon.test.tsx @@ -16,12 +16,14 @@ import { renderInTestApp } from '@backstage/test-utils'; import React from 'react'; -import { EntityKindIcon } from './EntityKindIcon'; +import { EntityIcon } from './EntityIcon'; +import MuiMemoryIcon from '@material-ui/icons/Memory'; +import { IconComponent } from '@backstage/core-plugin-api'; describe('', () => { it('renders without exploding', async () => { const { baseElement } = await renderInTestApp( - , + , ); expect(baseElement.querySelector('svg')).toBeInTheDocument(); @@ -29,7 +31,7 @@ describe('', () => { it('renders without exploding for unknown kind', async () => { const { baseElement } = await renderInTestApp( - , + , ); expect(baseElement.querySelector('svg')).toBeInTheDocument(); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityIcon.tsx similarity index 69% rename from plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.tsx rename to plugins/catalog-graph/src/components/EntityRelationsGraph/EntityIcon.tsx index 7263e25eae..a46a8bcc9d 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityIcon.tsx @@ -13,23 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useApp } from '@backstage/core-plugin-api'; import React from 'react'; import SvgIcon from '@material-ui/core/SvgIcon'; +import { OverridableComponent } from '@material-ui/core/OverridableComponent'; +import { SvgIconTypeMap } from '@material-ui/core/SvgIcon/SvgIcon'; +import { IconComponent } from '@backstage/core-plugin-api'; -export function EntityKindIcon({ - kind, +export function EntityIcon({ + icon, ...props }: { - kind: string; + icon: IconComponent | undefined; x?: number; y?: number; width?: number; height?: number; className?: string; }) { - const app = useApp(); - const Icon = - app.getSystemIcon(`kind:${kind.toLocaleLowerCase('en-US')}`) ?? SvgIcon; + const Icon = (icon as OverridableComponent) ?? SvgIcon; return ; } diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts index af2a491ada..07e3085f1f 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { Entity } from '@backstage/catalog-model'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { useEntityStore } from './useEntityStore'; import { pickBy } from 'lodash'; @@ -104,9 +104,13 @@ export function useEntityRelationGraph({ requestEntities, ]); - const filteredEntities = entityFilter - ? pickBy(entities, (value, _key) => entityFilter(value)) - : entities; + const filteredEntities = useMemo( + () => + entityFilter + ? pickBy(entities, (value, _key) => entityFilter(value)) + : entities, + [entities, entityFilter], + ); return { entities: filteredEntities, diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 455f094a86..2063f9e2f9 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,77 @@ # @backstage/plugin-catalog-import +## 0.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + +## 0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + +## 0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-catalog-common@1.0.25 + +## 0.12.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.12.1-next.2 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index f41d239792..44076a3fbc 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.12.1-next.2", + "version": "0.12.2-next.2", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts b/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts index a8fbe9db76..9f058dc744 100644 --- a/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts +++ b/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts @@ -26,7 +26,7 @@ import { RepoApiClient, } from './AzureRepoApiClient'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; function mockRepoEndpoint() { return rest.get( @@ -153,7 +153,7 @@ function mockPrEndpoint() { describe('RepoApiClient', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); const testToken = new Date().toString(); const sut = new RepoApiClient({ project: 'project', diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index 1f16840c33..fa646e3ca4 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -57,7 +57,7 @@ import { ConfigReader, UrlPatternDiscovery } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { ScmAuthApi } from '@backstage/integration-react'; import { CatalogApi } from '@backstage/plugin-catalog-react'; -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { Octokit } from '@octokit/rest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -70,7 +70,7 @@ import { describe('CatalogImportClient', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); const mockBaseUrl = 'http://backstage:9191/api/catalog'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 54f39e9e51..24f1446c6d 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,63 @@ # @backstage/plugin-catalog-node +## 1.12.5-next.2 + +### Patch Changes + +- 7c5f3b0: Explicit declare if the service ref accepts `single` or `multiple` implementations. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 1.12.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 1.12.5-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## 1.12.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.12.4-next.1 ### Patch Changes diff --git a/plugins/catalog-node/api-report-alpha.md b/plugins/catalog-node/api-report-alpha.md index b61d1b1d27..ba02079ceb 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; @@ -88,7 +96,7 @@ export interface CatalogProcessingExtensionPoint { export const catalogProcessingExtensionPoint: ExtensionPoint; // @alpha -export const catalogServiceRef: ServiceRef; +export const catalogServiceRef: ServiceRef; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 575a1c65f5..330427c7b5 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.12.4-next.1", + "version": "1.12.5-next.2", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", 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 */ diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index b29a49e47d..24a1cf6572 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,85 @@ # @backstage/plugin-catalog-react +## 1.12.3-next.2 + +### Patch Changes + +- 012e3eb: Entity page extensions created for the new frontend system via the `/alpha` exports will now be enabled by default. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## 1.12.3-next.1 + +### Patch Changes + +- 7ca331c: Correct `EntityDisplayName`'s icon alignment with the text. +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## 1.12.3-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- 9b89b82: Internal refactor to remove unnecessary `routable` prop in the implementation of the `createEntityContentExtension` alpha export. +- bebd569: Fix extra divider displayed on user list picker component +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-react@0.4.24 + +## 1.12.2 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- 2030962: Make EntityOwnerPicker display metadata.title or spec.profile.displayName for mode=only-owners instead of metadata.name +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.12.2-next.2 ### Patch Changes diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index b82c7ae3e2..206c0160e2 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -17,12 +17,21 @@ import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) export const catalogExtensionData: { - entityContentTitle: ConfigurableExtensionDataRef; - entityFilterFunction: ConfigurableExtensionDataRef< - (entity: Entity) => boolean, + entityContentTitle: ConfigurableExtensionDataRef< + string, + 'catalog.entity-content-title', + {} + >; + entityFilterFunction: ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + 'catalog.entity-filter-function', + {} + >; + entityFilterExpression: ConfigurableExtensionDataRef< + string, + 'catalog.entity-filter-expression', {} >; - entityFilterExpression: ConfigurableExtensionDataRef; }; // @alpha (undocumented) @@ -106,7 +115,7 @@ export function createEntityCardExtension< config: TConfig; inputs: Expand>; }) => Promise; -}): ExtensionDefinition; +}): ExtensionDefinition; // @alpha (undocumented) export function createEntityContentExtension< @@ -129,11 +138,18 @@ export function createEntityContentExtension< loader: (options: { inputs: Expand>; }) => Promise; -}): ExtensionDefinition<{ - title: string; - path: string; - filter?: string | undefined; -}>; +}): ExtensionDefinition< + { + title: string; + path: string; + filter?: string | undefined; + }, + { + filter?: string | undefined; + title?: string | undefined; + path?: string | undefined; + } +>; // @alpha export function isOwnerOf(owner: Entity, entity: Entity): boolean; diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index f522a4f111..7300729db5 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.12.2-next.2", + "version": "1.12.3-next.2", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index b1650d1f5b..42d69726b6 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -36,15 +36,15 @@ export * from './translation'; /** @alpha */ export const catalogExtensionData = { - entityContentTitle: createExtensionDataRef( - 'catalog.entity-content-title', - ), - entityFilterFunction: createExtensionDataRef<(entity: Entity) => boolean>( - 'catalog.entity-filter-function', - ), - entityFilterExpression: createExtensionDataRef( - 'catalog.entity-filter-expression', - ), + entityContentTitle: createExtensionDataRef().with({ + id: 'catalog.entity-content-title', + }), + entityFilterFunction: createExtensionDataRef< + (entity: Entity) => boolean + >().with({ id: 'catalog.entity-filter-function' }), + entityFilterExpression: createExtensionDataRef().with({ + id: 'catalog.entity-filter-expression', + }), }; // TODO: Figure out how to merge with provided config schema @@ -83,7 +83,7 @@ export function createEntityCardExtension< id: 'entity-content:catalog/overview', input: 'cards', }, - disabled: options.disabled ?? true, + disabled: options.disabled, output: { element: coreExtensionData.reactElement, filterFunction: catalogExtensionData.entityFilterFunction.optional(), @@ -137,7 +137,7 @@ export function createEntityContentExtension< id: 'page:catalog/entity', input: 'contents', }, - disabled: options.disabled ?? true, + disabled: options.disabled, output: { element: coreExtensionData.reactElement, path: coreExtensionData.routePath, @@ -166,7 +166,7 @@ export function createEntityContentExtension< title: config.title, routeRef: options.routeRef, element: ( - + ), diff --git a/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx b/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx index e953f21afb..68d5ecefdb 100644 --- a/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx +++ b/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx @@ -38,7 +38,9 @@ const useStyles = makeStyles( icon: { marginRight: theme.spacing(0.5), color: theme.palette.text.secondary, - lineHeight: 0, + '& svg': { + verticalAlign: 'middle', + }, }, }), { name: 'CatalogReactEntityDisplayName' }, diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx index 7f0ff8be74..c6b515aa67 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx @@ -247,11 +247,11 @@ export const UserListPicker = (props: UserListPickerProps) => { - {group.items.map(item => ( + {group.items.map((item, index) => ( setSelectedUserFilter(item.id)} selected={item.id === filters.user?.value} className={classes.menuItem} diff --git a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md index f2f489b6a0..b299631a21 100644 --- a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-unprocessed-entities-common +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + ## 0.0.2 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities-common/package.json b/plugins/catalog-unprocessed-entities-common/package.json index f491d27157..e5f88ebba4 100644 --- a/plugins/catalog-unprocessed-entities-common/package.json +++ b/plugins/catalog-unprocessed-entities-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities-common", - "version": "0.0.2", + "version": "0.0.4-next.1", "description": "Common functionalities for the catalog-unprocessed-entities plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index fefeffe9d2..2c2eb03f5e 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## 0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.2.6-next.1 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 142b850bd3..8ce8c8b0d3 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.2.6-next.1", + "version": "0.2.7-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 08a70d4956..48daaa7774 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,97 @@ # @backstage/plugin-catalog +## 1.22.0-next.2 + +### Minor Changes + +- 6925dcb: Introduces the HasSubdomainsCard component that displays the subdomains of a given domain + +### Patch Changes + +- 604a504: The entity relation cards available for the new frontend system via `/alpha` now have more accurate and granular default filters. +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-search-common@1.2.14-next.1 + - @backstage/plugin-search-react@1.7.14-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + +## 1.21.2-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-search-react@1.7.14-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/plugin-search-common@1.2.14-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + +## 1.21.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + +## 1.21.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- d133eaa: Added small notes to AboutCard to discourage customizability PRs +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-search-react@1.7.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.21.1-next.2 ### Patch Changes diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 102e2a7aa3..336bf4bc2b 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -85,6 +85,8 @@ export const catalogTranslationRef: TranslationRef< 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 'hasSubdomainsCard.title': 'Has subdomains'; + readonly 'hasSubdomainsCard.emptyMessage': 'No subdomain is part of this domain'; readonly 'hasSystemsCard.title': 'Has systems'; readonly 'hasSystemsCard.emptyMessage': 'No system is part of this domain'; readonly 'relatedEntitiesCard.emptyHelpLinkTitle': 'Learn how to change this.'; @@ -99,14 +101,14 @@ export const catalogTranslationRef: TranslationRef< // @alpha (undocumented) export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, - TConfig = never, + TConfig, >(options: { namespace?: string; name?: string; inputs?: TInputs; configSchema?: PortableSchema; loader: (options: { config: TConfig }) => Promise; -}): ExtensionDefinition; +}): ExtensionDefinition; // @alpha (undocumented) const _default: BackstagePlugin< @@ -119,23 +121,17 @@ const _default: BackstagePlugin< }>; }, { - viewTechDoc: ExternalRouteRef< - { - name: string; - kind: string; - namespace: string; - }, - true - >; - createComponent: ExternalRouteRef; - createFromTemplate: ExternalRouteRef< - { - namespace: string; - templateName: string; - }, - true - >; - unregisterRedirect: ExternalRouteRef; + viewTechDoc: ExternalRouteRef<{ + name: string; + kind: string; + namespace: string; + }>; + createComponent: ExternalRouteRef; + createFromTemplate: ExternalRouteRef<{ + namespace: string; + templateName: string; + }>; + unregisterRedirect: ExternalRouteRef; } >; export default _default; diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index c1fb52fb94..95333a6451 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -370,6 +370,11 @@ export const EntityHasSubcomponentsCard: ( props: HasSubcomponentsCardProps, ) => JSX.Element; +// @public (undocumented) +export const EntityHasSubdomainsCard: ( + props: HasSubdomainsCardProps, +) => JSX.Element; + // @public (undocumented) export const EntityHasSystemsCard: (props: HasSystemsCardProps) => JSX.Element; @@ -551,6 +556,16 @@ export interface HasSubcomponentsCardProps { variant?: InfoCardVariants; } +// @public (undocumented) +export interface HasSubdomainsCardProps { + // (undocumented) + tableOptions?: TableOptions; + // (undocumented) + title?: string; + // (undocumented) + variant?: InfoCardVariants; +} + // @public (undocumented) export interface HasSystemsCardProps { // (undocumented) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 0d101af3df..0208271d1a 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.21.1-next.2", + "version": "1.22.0-next.2", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx index 48ee647b81..d8a218f8f3 100644 --- a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx +++ b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx @@ -26,7 +26,7 @@ import { /** @alpha */ export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, - TConfig = never, + TConfig, >(options: { namespace?: string; name?: string; diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx index da6a6a669e..8a18efabde 100644 --- a/plugins/catalog/src/alpha/entityCards.tsx +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -46,6 +46,7 @@ export const catalogLabelsEntityCard = createEntityCardExtension({ export const catalogDependsOnComponentsEntityCard = createEntityCardExtension({ name: 'depends-on-components', + filter: 'kind:component', loader: async () => import('../components/DependsOnComponentsCard').then(m => compatWrapper(), @@ -54,6 +55,7 @@ export const catalogDependsOnComponentsEntityCard = createEntityCardExtension({ export const catalogDependsOnResourcesEntityCard = createEntityCardExtension({ name: 'depends-on-resources', + filter: 'kind:component', loader: async () => import('../components/DependsOnResourcesCard').then(m => compatWrapper(), @@ -62,6 +64,7 @@ export const catalogDependsOnResourcesEntityCard = createEntityCardExtension({ export const catalogHasComponentsEntityCard = createEntityCardExtension({ name: 'has-components', + filter: 'kind:system', loader: async () => import('../components/HasComponentsCard').then(m => compatWrapper(), @@ -70,6 +73,7 @@ export const catalogHasComponentsEntityCard = createEntityCardExtension({ export const catalogHasResourcesEntityCard = createEntityCardExtension({ name: 'has-resources', + filter: 'kind:system', loader: async () => import('../components/HasResourcesCard').then(m => compatWrapper(), @@ -78,14 +82,25 @@ export const catalogHasResourcesEntityCard = createEntityCardExtension({ export const catalogHasSubcomponentsEntityCard = createEntityCardExtension({ name: 'has-subcomponents', + filter: 'kind:component', loader: async () => import('../components/HasSubcomponentsCard').then(m => compatWrapper(), ), }); +export const catalogHasSubdomainsEntityCard = createEntityCardExtension({ + name: 'has-subdomains', + filter: 'kind:domain', + loader: async () => + import('../components/HasSubdomainsCard').then(m => + compatWrapper(), + ), +}); + export const catalogHasSystemsEntityCard = createEntityCardExtension({ name: 'has-systems', + filter: 'kind:domain', loader: async () => import('../components/HasSystemsCard').then(m => compatWrapper(), @@ -101,5 +116,6 @@ export default [ catalogHasComponentsEntityCard, catalogHasResourcesEntityCard, catalogHasSubcomponentsEntityCard, + catalogHasSubdomainsEntityCard, catalogHasSystemsEntityCard, ]; diff --git a/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.test.tsx b/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.test.tsx new file mode 100644 index 0000000000..6c145b3228 --- /dev/null +++ b/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.test.tsx @@ -0,0 +1,122 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity, RELATION_HAS_PART } from '@backstage/catalog-model'; +import { + CatalogApi, + catalogApiRef, + EntityProvider, + entityRouteRef, +} from '@backstage/plugin-catalog-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { waitFor, screen } from '@testing-library/react'; +import React from 'react'; +import { HasSubdomainsCard } from './HasSubdomainsCard'; + +describe('', () => { + const getEntitiesByRefs: jest.MockedFunction< + CatalogApi['getEntitiesByRefs'] + > = jest.fn(); + let Wrapper: React.ComponentType>; + + beforeEach(() => { + Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ); + }); + + afterEach(() => jest.resetAllMocks()); + + it('shows empty list if no relations', async () => { + const entity: Entity = { + apiVersion: 'v1', + kind: 'Domain', + metadata: { + name: 'my-domain', + namespace: 'my-namespace', + }, + relations: [], + }; + + await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ); + + expect(screen.getByText('Has subdomains')).toBeInTheDocument(); + expect( + screen.getByText(/No subdomain is part of this domain/i), + ).toBeInTheDocument(); + }); + + it('shows related subdomains', async () => { + const entity: Entity = { + apiVersion: 'v1', + kind: 'Domain', + metadata: { + name: 'my-domain', + namespace: 'my-namespace', + }, + relations: [ + { + targetRef: 'domain:my-namespace/target-name', + type: RELATION_HAS_PART, + }, + ], + }; + getEntitiesByRefs.mockResolvedValue({ + items: [ + { + apiVersion: 'v1', + kind: 'Domain', + metadata: { + name: 'target-name', + namespace: 'my-namespace', + }, + spec: {}, + }, + ], + }); + + await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ); + + await waitFor(() => { + expect(screen.getByText('Has subdomains')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.tsx b/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.tsx new file mode 100644 index 0000000000..811f74d820 --- /dev/null +++ b/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.tsx @@ -0,0 +1,55 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RELATION_HAS_PART } from '@backstage/catalog-model'; +import { InfoCardVariants, TableOptions } from '@backstage/core-components'; +import React from 'react'; +import { + asComponentEntities, + componentEntityColumns, + RelatedEntitiesCard, +} from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; + +/** @public */ +export interface HasSubdomainsCardProps { + variant?: InfoCardVariants; + tableOptions?: TableOptions; + title?: string; +} + +export function HasSubdomainsCard(props: HasSubdomainsCardProps) { + const { t } = useTranslationRef(catalogTranslationRef); + const { + variant = 'gridItem', + tableOptions = {}, + title = t('hasSubdomainsCard.title'), + } = props; + return ( + + ); +} diff --git a/plugins/catalog/src/components/HasSubdomainsCard/index.ts b/plugins/catalog/src/components/HasSubdomainsCard/index.ts new file mode 100644 index 0000000000..a740abbcc2 --- /dev/null +++ b/plugins/catalog/src/components/HasSubdomainsCard/index.ts @@ -0,0 +1,18 @@ +/* + * 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 { HasSubdomainsCard } from './HasSubdomainsCard'; +export type { HasSubdomainsCardProps } from './HasSubdomainsCard'; diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts index a691011c96..806ea40c66 100644 --- a/plugins/catalog/src/index.ts +++ b/plugins/catalog/src/index.ts @@ -49,6 +49,7 @@ export { EntityHasComponentsCard, EntityHasResourcesCard, EntityHasSubcomponentsCard, + EntityHasSubdomainsCard, EntityHasSystemsCard, EntityLinksCard, EntityLabelsCard, @@ -71,6 +72,7 @@ export type { EntityContextMenuClassKey } from './components/EntityContextMenu'; export type { HasComponentsCardProps } from './components/HasComponentsCard'; export type { HasResourcesCardProps } from './components/HasResourcesCard'; export type { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard'; +export type { HasSubdomainsCardProps } from './components/HasSubdomainsCard'; export type { HasSystemsCardProps } from './components/HasSystemsCard'; export type { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard'; export type { CatalogSearchResultListItemProps } from './components/CatalogSearchResultListItem'; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 33ceaef632..a339ff31a8 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -50,6 +50,7 @@ import { DependsOnResourcesCardProps } from './components/DependsOnResourcesCard import { HasComponentsCardProps } from './components/HasComponentsCard'; import { HasResourcesCardProps } from './components/HasResourcesCard'; import { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard'; +import { HasSubdomainsCardProps } from './components/HasSubdomainsCard'; import { HasSystemsCardProps } from './components/HasSystemsCard'; import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard'; import { CatalogSearchResultListItemProps } from './components/CatalogSearchResultListItem'; @@ -199,6 +200,19 @@ export const EntityHasSubcomponentsCard: ( }), ); +/** @public */ +export const EntityHasSubdomainsCard: ( + props: HasSubdomainsCardProps, +) => JSX.Element = catalogPlugin.provide( + createComponentExtension({ + name: 'EntityHasSubdomainsCard', + component: { + lazy: () => + import('./components/HasSubdomainsCard').then(m => m.HasSubdomainsCard), + }, + }), +); + /** @public */ export const EntityHasResourcesCard: ( props: HasResourcesCardProps, diff --git a/plugins/catalog/src/translation.ts b/plugins/catalog/src/translation.ts index 2699b58542..f38a34be84 100644 --- a/plugins/catalog/src/translation.ts +++ b/plugins/catalog/src/translation.ts @@ -143,6 +143,10 @@ export const catalogTranslationRef = createTranslationRef({ title: 'Has subcomponents', emptyMessage: 'No subcomponent is part of this component', }, + hasSubdomainsCard: { + title: 'Has subdomains', + emptyMessage: 'No subdomain is part of this domain', + }, hasSystemsCard: { title: 'Has systems', emptyMessage: 'No system is part of this domain', diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 8458a50aa3..c11499f589 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-config-schema +## 0.1.58-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.1.57 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.1.57-next.1 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 9a1971d80b..ad98b78b98 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-config-schema", - "version": "0.1.57-next.1", + "version": "0.1.58-next.0", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index cc0dc806c8..db4d04fc6e 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,71 @@ # @backstage/plugin-devtools-backend +## 0.3.9-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config-loader@1.9.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-devtools-common@0.1.12-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.0-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-devtools-common@0.1.12-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.3.9-next.0 + +### Patch Changes + +- 32a38e1: Removed unused code for lockfile analysis. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## 0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/config-loader@1.8.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.3.8-next.1 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index bd3b61f22d..64cfc4f883 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.3.8-next.1", + "version": "0.3.9-next.2", "backstage": { "role": "backend-plugin", "pluginId": "devtools", @@ -56,7 +56,7 @@ "express-promise-router": "^4.1.0", "fs-extra": "^11.0.0", "lodash": "^4.17.21", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "ping": "^0.4.1", "semver": "^7.5.3", "yn": "^4.0.0" diff --git a/plugins/devtools-backend/src/util/Lockfile.ts b/plugins/devtools-backend/src/util/Lockfile.ts index 52dbb847bc..7f5497e948 100644 --- a/plugins/devtools-backend/src/util/Lockfile.ts +++ b/plugins/devtools-backend/src/util/Lockfile.ts @@ -15,7 +15,6 @@ */ import fs from 'fs-extra'; -import semver from 'semver'; import { parseSyml, stringifySyml } from '@yarnpkg/parsers'; import { stringify as legacyStringifyLockfile } from '@yarnpkg/lockfile'; @@ -35,35 +34,6 @@ type LockfileQueryEntry = { version: string; }; -/** Entries that have an invalid version range, for example an npm tag */ -type AnalyzeResultInvalidRange = { - name: string; - range: string; -}; - -/** Entries that can be deduplicated by bumping to an existing higher version */ -type AnalyzeResultNewVersion = { - name: string; - range: string; - oldVersion: string; - newVersion: string; -}; - -/** Entries that would need a dependency update in package.json to be deduplicated */ -type AnalyzeResultNewRange = { - name: string; - oldRange: string; - newRange: string; - oldVersion: string; - newVersion: string; -}; - -type AnalyzeResult = { - invalidRanges: AnalyzeResultInvalidRange[]; - newVersions: AnalyzeResultNewVersion[]; - newRanges: AnalyzeResultNewRange[]; -}; - function parseLockfile(lockfileContents: string) { try { return { @@ -135,11 +105,10 @@ export class Lockfile { queries.push({ range, version: value.version }); } - return new Lockfile(path, packages, data, legacy); + return new Lockfile(packages, data, legacy); } private constructor( - private readonly path: string, private readonly packages: Map, private readonly data: LockfileData, private readonly legacy: boolean = false, @@ -155,162 +124,6 @@ export class Lockfile { return this.packages.keys(); } - /** Analyzes the lockfile to identify possible actions and warnings for the entries */ - analyze(options?: { filter?: (name: string) => boolean }): AnalyzeResult { - const { filter } = options ?? {}; - const result: AnalyzeResult = { - invalidRanges: [], - newVersions: [], - newRanges: [], - }; - - for (const [name, allEntries] of this.packages) { - if (filter && !filter(name)) { - continue; - } - - // Get rid of and signal any invalid ranges upfront - const invalid = allEntries.filter(e => !semver.validRange(e.range)); - result.invalidRanges.push( - ...invalid.map(({ range }) => ({ name, range })), - ); - - // Grab all valid entries, if there aren't at least 2 different valid ones we're done - const entries = allEntries.filter(e => semver.validRange(e.range)); - if (entries.length < 2) { - continue; - } - - // Find all versions currently in use - const versions = Array.from(new Set(entries.map(e => e.version))).sort( - (v1, v2) => semver.rcompare(v1, v2), - ); - - // If we're not using at least 2 different versions we're done - if (versions.length < 2) { - continue; - } - - const acceptedVersions = new Set(); - for (const { version, range } of entries) { - // Finds the highest matching version from the the known versions - // TODO(Rugvip): We may want to select the version that satisfies the most ranges rather than the highest one - const acceptedVersion = versions.find(v => semver.satisfies(v, range)); - if (!acceptedVersion) { - throw new Error( - `No existing version was accepted for range ${range}, searching through ${versions}, for package ${name}`, - ); - } - - if (acceptedVersion !== version) { - result.newVersions.push({ - name, - range, - newVersion: acceptedVersion, - oldVersion: version, - }); - } - - acceptedVersions.add(acceptedVersion); - } - - // If all ranges were able to accept the same version, we're done - if (acceptedVersions.size === 1) { - continue; - } - - // Find the max version that we may want bump older packages to - const maxVersion = Array.from(acceptedVersions).sort(semver.rcompare)[0]; - // Find all existing ranges that satisfy the new max version, and pick the one that - // results in the highest minimum allowed version, usually being the more specific one - const maxEntry = entries - .filter(e => semver.satisfies(maxVersion, e.range)) - .map(e => ({ e, min: semver.minVersion(e.range) })) - .filter(p => p.min) - .sort((a, b) => semver.rcompare(a.min!, b.min!))[0]?.e; - if (!maxEntry) { - throw new Error( - `No entry found that satisfies max version '${maxVersion}'`, - ); - } - - // Find all entries that don't satisfy the max version - for (const { version, range } of entries) { - if (semver.satisfies(maxVersion, range)) { - continue; - } - - result.newRanges.push({ - name, - oldRange: range, - newRange: maxEntry.range, - oldVersion: version, - newVersion: maxVersion, - }); - } - } - - return result; - } - - remove(name: string, range: string): boolean { - const query = `${name}@${range}`; - const existed = Boolean(this.data[query]); - delete this.data[query]; - - const newEntries = this.packages.get(name)?.filter(e => e.range !== range); - if (newEntries) { - this.packages.set(name, newEntries); - } - - return existed; - } - - /** Modifies the lockfile by bumping packages to the suggested versions */ - replaceVersions(results: AnalyzeResultNewVersion[]) { - for (const { name, range, oldVersion, newVersion } of results) { - const query = `${name}@${range}`; - - // Update the backing data - const entryData = this.data[query]; - if (!entryData) { - throw new Error(`No entry data for ${query}`); - } - if (entryData.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - - // Modifying the data in the entry is not enough, we need to reference an existing version object - const matchingEntry = Object.entries(this.data).find( - ([q, e]) => q.startsWith(`${name}@`) && e.version === newVersion, - ); - if (!matchingEntry) { - throw new Error( - `No matching entry found for ${name} at version ${newVersion}`, - ); - } - this.data[query] = matchingEntry[1]; - - // Update our internal data structure - const entry = this.packages.get(name)?.find(e => e.range === range); - if (!entry) { - throw new Error(`No entry data for ${query}`); - } - if (entry.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - entry.version = newVersion; - } - } - - async save() { - await fs.writeFile(this.path, this.toString(), 'utf8'); - } - toString() { return stringifyLockfile(this.data, this.legacy); } diff --git a/plugins/devtools-common/CHANGELOG.md b/plugins/devtools-common/CHANGELOG.md index 3e060571ad..80d0584c77 100644 --- a/plugins/devtools-common/CHANGELOG.md +++ b/plugins/devtools-common/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-devtools-common +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/types@1.1.1 + +## 0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/types@1.1.1 + +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/types@1.1.1 + ## 0.1.10 ### Patch Changes diff --git a/plugins/devtools-common/package.json b/plugins/devtools-common/package.json index 24b17d6742..d8a87753ca 100644 --- a/plugins/devtools-common/package.json +++ b/plugins/devtools-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-common", - "version": "0.1.10", + "version": "0.1.12-next.1", "description": "Common functionalities for the devtools plugin", "backstage": { "role": "common-library", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 5bc6220aa3..afebfeefe2 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-devtools +## 0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-devtools-common@0.1.12-next.1 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-devtools-common@0.1.12-next.0 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-react@0.4.24 + +## 0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.1.16-next.1 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 90d724692c..264f7af95b 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.16-next.1", + "version": "0.1.17-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index 399ed2689d..a4a4da2b17 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.3.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## 0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/backend-tasks@0.5.28-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.3.9-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.3.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index b2c09d3b8a..7b1da53130 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.3.8-next.1", + "version": "0.3.9-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts index 26eba88c18..de55dee017 100644 --- a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts @@ -76,6 +76,7 @@ export class AwsSqsConsumingEventPublisher { }; this.sqs = new SQSClient({ + customUserAgent: 'backstage-aws-events-sqs-publisher', region: config.region, endpoint: config.endpoint, }); diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 5e5ccffc2a..804293b869 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-events-backend-module-azure +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 8bb6ac4f6b..5d7fc3f1bf 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.2.8-next.1", + "version": "0.2.9-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 1a339c3807..edef56d946 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 7efffdd361..a58bacdf8c 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.2.8-next.1", + "version": "0.2.9-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index 78963fbbaf..fcdda38e9b 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index f1bea2868c..91e598511f 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.2.8-next.1", + "version": "0.2.9-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index a095cf4ab3..38b1e277e8 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-events-backend-module-github +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index 3b37f29022..f77c2c9df8 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.2.8-next.1", + "version": "0.2.9-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index dc8470bd7a..a7986891fa 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 21c95448b1..c5a0abfeb8 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.2.8-next.1", + "version": "0.2.9-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 967ffc80da..f408883694 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.2 + +## 0.1.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.1.32 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.8 + ## 0.1.32-next.1 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 120c7f5fa6..0cff95bf35 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.32-next.1", + "version": "0.1.33-next.2", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index a4b4b550bb..8c2e2f767b 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-events-backend +## 0.3.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/config@1.2.0 + +## 0.3.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.1 + +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## 0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + ## 0.3.9-next.1 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 82066d5a91..01310be5d8 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.3.9-next.1", + "version": "0.3.10-next.2", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 022d50fdd1..ec7c864d23 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-events-node +## 0.3.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + +## 0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + +## 0.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + +## 0.3.8 + +### Patch Changes + +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + ## 0.3.8-next.1 ### Patch Changes diff --git a/plugins/events-node/api-report.md b/plugins/events-node/api-report.md index 46646d2ce8..729f526dee 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,13 +63,15 @@ export interface EventsService { export type EventsServiceEventHandler = (params: EventParams) => Promise; // @public (undocumented) -export const eventsServiceFactory: () => ServiceFactory< +export const eventsServiceFactory: ServiceFactoryCompat< EventsService, - 'plugin' + 'plugin', + 'singleton', + undefined >; // @public -export const eventsServiceRef: ServiceRef; +export const eventsServiceRef: ServiceRef; // @public (undocumented) export type EventsServiceSubscribeOptions = { diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index f89617dd14..db2a6f4271 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.3.8-next.1", + "version": "0.3.9-next.2", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index d1553258ed..370053d097 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,45 @@ # @internal/plugin-todo-list-backend +## 1.0.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/errors@1.2.4 + +## 1.0.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## 1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + ## 1.0.29-next.1 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 3d46a9f5f7..b9b04c178f 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.29-next.1", + "version": "1.0.30-next.2", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index 3761ead6a3..b2f2175573 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,26 @@ # @internal/plugin-todo-list-common +## 1.0.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + +## 1.0.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + +## 1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + ## 1.0.19 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 317cfa991d..cca7f5aa4b 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.19", + "version": "1.0.21-next.1", "backstage": { "role": "common-library", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index f61f8b8d0a..51e2b93ef9 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,21 @@ # @internal/plugin-todo-list +## 1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## 1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + ## 1.0.29-next.1 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index d008b73538..d950d8c406 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.29-next.1", + "version": "1.0.30-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 1f1c9a0e2e..d810195e7f 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-home-react +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.1.15 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.15-next.2 ### Patch Changes diff --git a/plugins/home-react/catalog-info.yaml b/plugins/home-react/catalog-info.yaml index 28109b9ddc..7022206fb9 100644 --- a/plugins/home-react/catalog-info.yaml +++ b/plugins/home-react/catalog-info.yaml @@ -9,4 +9,4 @@ metadata: spec: lifecycle: experimental type: backstage-web-library - owner: discoverability-maintainers + owner: home-maintainers diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index ec05852818..00b0f29fca 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.15-next.2", + "version": "0.1.16-next.0", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index e65b3dec1c..08cf9bec5f 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,79 @@ # @backstage/plugin-home +## 0.7.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + +## 0.7.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + +## 0.7.8-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- fdcc059: Fixed a bug on the WelcomeTitle component where the welcome message wasn't correct when the language was set to Spanish +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + +## 0.7.7 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-home-react@0.1.15 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 0.7.7-next.2 ### Patch Changes diff --git a/plugins/home/api-report-alpha.md b/plugins/home/api-report-alpha.md index 35ce0bb86c..eb693a8e6f 100644 --- a/plugins/home/api-report-alpha.md +++ b/plugins/home/api-report-alpha.md @@ -11,7 +11,11 @@ const _default: BackstagePlugin<{}, {}>; export default _default; // @alpha (undocumented) -export const titleExtensionDataRef: ConfigurableExtensionDataRef; +export const titleExtensionDataRef: ConfigurableExtensionDataRef< + string, + 'title', + {} +>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/home/catalog-info.yaml b/plugins/home/catalog-info.yaml index 1b23d4b83b..eefc114313 100644 --- a/plugins/home/catalog-info.yaml +++ b/plugins/home/catalog-info.yaml @@ -7,4 +7,4 @@ metadata: spec: lifecycle: experimental type: backstage-frontend-plugin - owner: discoverability-maintainers + owner: home-maintainers diff --git a/plugins/home/package.json b/plugins/home/package.json index 01dd27a295..e566b46e78 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.7.7-next.2", + "version": "0.7.9-next.2", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index e9ff26c9e1..b13c2a2e0e 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -31,7 +31,9 @@ const rootRouteRef = createRouteRef(); /** * @alpha */ -export const titleExtensionDataRef = createExtensionDataRef('title'); +export const titleExtensionDataRef = createExtensionDataRef().with({ + id: 'title', +}); const homePage = createPageExtension({ defaultPath: '/home', diff --git a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json index 9010ba4359..ddb51654fa 100644 --- a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json +++ b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json @@ -103,6 +103,7 @@ "Sinhala": "සුභ දවාලක්", "Slovenian": "Dober dan", "Somali": "Galab wanaagsan", + "Spanish": "Buenas tardes", "Southern Sámi": "Buerie biejjie", "Sumerian": "𒄭𒌓𒁀", "Swahili": "Habari ya mchana", diff --git a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json index 5a98abafaa..c8d8c7334e 100644 --- a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json +++ b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json @@ -85,7 +85,7 @@ "Slovak": "Dober vecher", "Slovenian": "Dober vecher", "Somali": "Habeen wanaagsan", - "Spanish": "Buenas tardes", + "Spanish": "Buenas noches", "Sumerian": "𒄭𒈪", "Swedish": "God afton", "Tagalog": "Magandang gabi", diff --git a/plugins/home/src/plugin.test.ts b/plugins/home/src/plugin.test.ts index 1526bd0c61..904481c98e 100644 --- a/plugins/home/src/plugin.test.ts +++ b/plugins/home/src/plugin.test.ts @@ -24,7 +24,7 @@ describe('home', () => { // Temporarily ensure we are installing a working version of the react-grid-layout library // For more details, see: https://github.com/react-grid-layout/react-grid-layout/issues/1959 - // TODO(@backstage/discoverability-maintainers): Delete this once the sub-dependency issue has been resolved. + // TODO(@backstage/home-maintainers): Delete this once the sub-dependency issue has been resolved. it('should pin react-grid-layout version to 1.3.4', async () => { expect(packageJson.dependencies['react-grid-layout']).toBe('1.3.4'); }); diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 7b8d3fb534..1255d6d0fd 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,88 @@ # @backstage/plugin-kubernetes-backend +## 0.18.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 8c1aa06: Add `kubernetes.clusterLocatorMethods[].clusters[].customResources` to the configuration schema. + This was already documented and supported by the plugin. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-kubernetes-node@0.1.17-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/integration-aws-node@0.1.12 + - @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.18.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-kubernetes-common@0.8.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 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-kubernetes-node@0.1.17-next.1 + +## 0.18.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-node@0.1.17-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## 0.18.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-node@0.1.16 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.18.3-next.1 ### Patch Changes diff --git a/plugins/kubernetes-backend/config.d.ts b/plugins/kubernetes-backend/config.d.ts index 777a3392db..d6c5f1d32b 100644 --- a/plugins/kubernetes-backend/config.d.ts +++ b/plugins/kubernetes-backend/config.d.ts @@ -68,6 +68,11 @@ export interface Config { caData?: string; /** @visibility secret */ caFile?: string; + customResources?: Array<{ + group: string; + apiVersion: string; + plural: string; + }>; }>; } | { diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index c9d8733319..70f640e0ba 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.18.3-next.1", + "version": "0.18.4-next.2", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", @@ -92,7 +92,7 @@ "lodash": "^4.17.21", "luxon": "^3.0.0", "morgan": "^1.10.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "stream-buffers": "^3.0.2", "winston": "^3.2.1", "yn": "^4.0.0" diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 1ac653bb58..5edb8845d4 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -38,7 +38,7 @@ import { ServiceMock, mockCredentials, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; @@ -508,7 +508,7 @@ describe('API integration tests', () => { describe('/proxy', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { worker.use( diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index a433374a2c..3491268d39 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -28,7 +28,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { FetchResponse, @@ -1128,7 +1128,7 @@ describe('KubernetesFanOutHandler', () => { describe('with a real fetcher', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); it('fetch error short-circuits requests to a single cluster, recovering across the fleet', async () => { const pods = [{ metadata: { name: 'pod-name' } }]; diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index dafb073bb1..8666e0ef16 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -28,7 +28,7 @@ import { setupServer } from 'msw/node'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { Config } from '@kubernetes/client-node'; @@ -71,7 +71,7 @@ const POD_METRICS_FIXTURE = [ describe('KubernetesFetcher', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); const labels = (req: MockedRequest): object => { const selectorParam = req.url.searchParams.get('labelSelector'); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 02eeb8c7ed..fe4feaee11 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -20,7 +20,7 @@ import { errorHandler } from '@backstage/backend-common'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { NotFoundError } from '@backstage/errors'; import { @@ -90,7 +90,7 @@ describe('KubernetesProxy', () => { getExternalBaseUrl: jest.fn(), }; - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); const buildMockRequest = (clusterName: any, path: string): Request => { const req = getMockReq({ diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 8932454b3c..801c2018c9 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.2 + +## 0.0.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.1 + +## 0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + +## 0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.0.13-next.2 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 3c6e6c8f1b..75c0758ac5 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.13-next.2", + "version": "0.0.14-next.2", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index e4de39bfd9..f8ac4b4768 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-kubernetes-common +## 0.8.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## 0.8.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## 0.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + ## 0.8.0 ### Minor Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 9005c5ffe9..1e05ed873e 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-common", - "version": "0.8.0", + "version": "0.8.2-next.1", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 4a6514a2d0..42e5885c49 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-kubernetes-node +## 0.1.17-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + +## 0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + ## 0.1.16-next.1 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 461bf1bbbe..5377f26b4d 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.1.16-next.1", + "version": "0.1.17-next.2", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", @@ -43,7 +43,7 @@ "@backstage/plugin-kubernetes-common": "workspace:^", "@backstage/types": "workspace:^", "@kubernetes/client-node": "^0.20.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "winston": "^3.2.1" }, "devDependencies": { diff --git a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts index fdfea030a5..24cd459fde 100644 --- a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts +++ b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts @@ -18,7 +18,7 @@ import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ClusterDetails } from '../types'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { createBackendModule } from '@backstage/backend-plugin-api'; @@ -43,7 +43,7 @@ describe('Pinniped - tokenCredentialRequest', () => { const logger = loggerToWinstonLogger(mockServices.logger.mock()); let httpsRequest: jest.SpyInstance; const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeAll(() => { httpsRequest = jest.spyOn( diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index 3755d259a8..34e9b259be 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-kubernetes-react +## 0.4.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + +## 0.4.1 + +### Patch Changes + +- e3cb6ab: Add a namespace label to RolloutDrawer +- 2414d86: Fix the `HTML` markup of the `FixDialog` component, `ul` and `li` are not allowed inside a `p` tag. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.1-next.1 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index fc6f382d3d..dbf89ae0cf 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-react", - "version": "0.4.1-next.1", + "version": "0.4.2-next.2", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", diff --git a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts index 82ac7c84e2..4698f01dfe 100644 --- a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts @@ -19,7 +19,7 @@ import { KubernetesBackendClient } from './KubernetesBackendClient'; import { rest } from 'msw'; import { UrlPatternDiscovery } from '@backstage/core-app-api'; import { setupServer } from 'msw/node'; -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { CustomObjectsByEntityRequest, KubernetesRequestBody, @@ -36,7 +36,7 @@ describe('KubernetesBackendClient', () => { }; let mockResponse: ObjectsByEntityResponse; const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); const identityApi = { getCredentials: jest.fn(), diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index a6d07dc706..1b5ca07506 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-kubernetes +## 0.11.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-kubernetes-common@0.8.2-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.2 + +## 0.11.13-next.1 + +### Patch Changes + +- e6c15cc: Adds support for Backstage's new frontend system, available via the `/alpha` sub-path export. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-kubernetes-common@0.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.2-next.1 + +## 0.11.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + +## 0.11.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.11.12-next.2 ### Patch Changes diff --git a/plugins/kubernetes/README.md b/plugins/kubernetes/README.md index 15dfd16b17..4ffde719f2 100644 --- a/plugins/kubernetes/README.md +++ b/plugins/kubernetes/README.md @@ -26,8 +26,38 @@ For more information, see the [formal documentation about the Kubernetes feature ## Getting started -Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/kubernetes](http://localhost:3000/kubernetes). +Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/kubernetes](http://localhost:3000/catalog/default/component/:component-name/kubernetes). You can also serve the plugin in isolation by running `yarn start` in the plugin directory. This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. + +### Integrating with `EntityPage` (New Frontend System) + +Follow this section if you are using Backstage's [new frontend system](https://backstage.io/docs/frontend-system/). + +1. Import `kubernetesPlugin` in your `App.tsx` and add it to your app's `features` array: + +```typescript +import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha'; + +// ... + +export const app = createApp({ + features: [ + // ... + kubernetesPlugin, + // ... + ], +}); +``` + +2. Next, enable your desired extensions in `app-config.yaml` + +```yaml +app: + extensions: + - entity-content:kubernetes/kubernetes +``` + +Now, the extension appears on your entity page as one of the tabs, which is called `KUBERNETES` diff --git a/plugins/kubernetes/api-report-alpha.md b/plugins/kubernetes/api-report-alpha.md new file mode 100644 index 0000000000..8bd6e98baa --- /dev/null +++ b/plugins/kubernetes/api-report-alpha.md @@ -0,0 +1,19 @@ +## API Report File for "@backstage/plugin-kubernetes" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; + +// @public (undocumented) +const _default: BackstagePlugin< + { + kubernetes: RouteRef; + }, + {} +>; +export default _default; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index d0ee97a882..ab8fe84d9b 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.11.12-next.2", + "version": "0.11.13-next.2", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", @@ -14,9 +14,7 @@ ] }, "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" }, "keywords": [ "backstage", @@ -30,8 +28,23 @@ }, "license": "Apache-2.0", "sideEffects": false, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, "main": "src/index.ts", "types": "src/index.ts", + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } + }, "files": [ "dist" ], @@ -46,8 +59,10 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", "@backstage/plugin-kubernetes-react": "workspace:^", diff --git a/plugins/kubernetes/src/alpha.ts b/plugins/kubernetes/src/alpha.ts new file mode 100644 index 0000000000..e80f131817 --- /dev/null +++ b/plugins/kubernetes/src/alpha.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './alpha/index'; +export { default } from './alpha/index'; diff --git a/plugins/kubernetes/src/alpha/KubernetesContentPage.tsx b/plugins/kubernetes/src/alpha/KubernetesContentPage.tsx new file mode 100644 index 0000000000..948a492e63 --- /dev/null +++ b/plugins/kubernetes/src/alpha/KubernetesContentPage.tsx @@ -0,0 +1,24 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useEntity } from '@backstage/plugin-catalog-react'; +import { KubernetesContent } from '../KubernetesContent'; +import React from 'react'; + +export function KubernetesContentPage() { + const { entity } = useEntity(); + return ; +} diff --git a/plugins/kubernetes/src/alpha/apis.tsx b/plugins/kubernetes/src/alpha/apis.tsx new file mode 100644 index 0000000000..6c880d2f53 --- /dev/null +++ b/plugins/kubernetes/src/alpha/apis.tsx @@ -0,0 +1,119 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createApiExtension, + createApiFactory, + discoveryApiRef, + fetchApiRef, +} from '@backstage/frontend-plugin-api'; +import { + KubernetesBackendClient, + kubernetesApiRef, + kubernetesProxyApiRef, + kubernetesAuthProvidersApiRef, + KubernetesAuthProviders, + KubernetesProxyClient, + kubernetesClusterLinkFormatterApiRef, + getDefaultFormatters, + KubernetesClusterLinkFormatter, + DEFAULT_FORMATTER_NAME, +} from '@backstage/plugin-kubernetes-react'; +import { + gitlabAuthApiRef, + googleAuthApiRef, + microsoftAuthApiRef, + oktaAuthApiRef, + oneloginAuthApiRef, +} from '@backstage/core-plugin-api'; + +export const kubernetesApiExtension = createApiExtension({ + factory: createApiFactory({ + api: kubernetesApiRef, + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + kubernetesAuthProvidersApi: kubernetesAuthProvidersApiRef, + }, + factory: ({ discoveryApi, fetchApi, kubernetesAuthProvidersApi }) => + new KubernetesBackendClient({ + discoveryApi, + fetchApi, + kubernetesAuthProvidersApi, + }), + }), +}); + +export const kubernetesProxyApi = createApiExtension({ + factory: createApiFactory({ + api: kubernetesProxyApiRef, + deps: { + kubernetesApi: kubernetesApiRef, + }, + factory: ({ kubernetesApi }) => + new KubernetesProxyClient({ + kubernetesApi, + }), + }), +}); + +export const kubernetesAuthProvidersApi = createApiExtension({ + factory: createApiFactory({ + api: kubernetesAuthProvidersApiRef, + deps: { + gitlabAuthApi: gitlabAuthApiRef, + googleAuthApi: googleAuthApiRef, + microsoftAuthApi: microsoftAuthApiRef, + oktaAuthApi: oktaAuthApiRef, + oneloginAuthApi: oneloginAuthApiRef, + }, + factory: ({ + gitlabAuthApi, + googleAuthApi, + microsoftAuthApi, + oktaAuthApi, + oneloginAuthApi, + }) => { + const oidcProviders = { + gitlab: gitlabAuthApi, + google: googleAuthApi, + microsoft: microsoftAuthApi, + okta: oktaAuthApi, + onelogin: oneloginAuthApi, + }; + + return new KubernetesAuthProviders({ + microsoftAuthApi, + googleAuthApi, + oidcProviders, + }); + }, + }), +}); + +export const kubernetesClusterLinkFormatterApi = createApiExtension({ + factory: createApiFactory({ + api: kubernetesClusterLinkFormatterApiRef, + deps: { googleAuthApi: googleAuthApiRef }, + factory: deps => { + const formatters = getDefaultFormatters(deps); + return new KubernetesClusterLinkFormatter({ + formatters, + defaultFormatterName: DEFAULT_FORMATTER_NAME, + }); + }, + }), +}); diff --git a/plugins/kubernetes/src/alpha/entityContents.tsx b/plugins/kubernetes/src/alpha/entityContents.tsx new file mode 100644 index 0000000000..9ad0b6843f --- /dev/null +++ b/plugins/kubernetes/src/alpha/entityContents.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; +import { createEntityContentExtension } from '@backstage/plugin-catalog-react/alpha'; +import { rootCatalogKubernetesRouteRef } from '../plugin'; + +export const entityKubernetesContent = createEntityContentExtension({ + defaultPath: 'kubernetes', + defaultTitle: 'Kubernetes', + name: 'kubernetes', + routeRef: convertLegacyRouteRef(rootCatalogKubernetesRouteRef), + loader: () => + import('./KubernetesContentPage').then(m => + compatWrapper(), + ), +}); diff --git a/plugins/kubernetes/src/alpha/index.ts b/plugins/kubernetes/src/alpha/index.ts new file mode 100644 index 0000000000..2f137f09ee --- /dev/null +++ b/plugins/kubernetes/src/alpha/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default } from './plugin'; diff --git a/plugins/kubernetes/src/alpha/pages.tsx b/plugins/kubernetes/src/alpha/pages.tsx new file mode 100644 index 0000000000..8b5db150bd --- /dev/null +++ b/plugins/kubernetes/src/alpha/pages.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; // Add this line to import React + +import { createPageExtension } from '@backstage/frontend-plugin-api'; +import { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; +import { rootCatalogKubernetesRouteRef } from '../plugin'; + +export const kubernetesPage = createPageExtension({ + defaultPath: '/kubernetes', + // you can reuse the existing routeRef + // by wrapping into the convertLegacyRouteRef. + routeRef: convertLegacyRouteRef(rootCatalogKubernetesRouteRef), + // these inputs usually match the props required by the component. + loader: () => import('../Router').then(m => compatWrapper()), +}); diff --git a/plugins/kubernetes/src/alpha/plugin.tsx b/plugins/kubernetes/src/alpha/plugin.tsx new file mode 100644 index 0000000000..47433bce35 --- /dev/null +++ b/plugins/kubernetes/src/alpha/plugin.tsx @@ -0,0 +1,40 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { convertLegacyRouteRefs } from '@backstage/core-compat-api'; +import { createPlugin } from '@backstage/frontend-plugin-api'; +import { kubernetesPage } from './pages'; +import { entityKubernetesContent } from './entityContents'; +import { rootCatalogKubernetesRouteRef } from '../plugin'; +import { + kubernetesApiExtension as kubernetesApi, + kubernetesAuthProvidersApi, + kubernetesClusterLinkFormatterApi, + kubernetesProxyApi, +} from './apis'; + +export default createPlugin({ + id: 'kubernetes', + extensions: [ + kubernetesPage, + entityKubernetesContent, + kubernetesApi, + kubernetesProxyApi, + kubernetesAuthProvidersApi, + kubernetesClusterLinkFormatterApi, + ], + routes: convertLegacyRouteRefs({ kubernetes: rootCatalogKubernetesRouteRef }), +}); diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index c536369352..a0b4bc8caa 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,112 @@ # @backstage/plugin-notifications-backend-module-email +## 0.2.0-next.2 + +### Patch Changes + +- cdb630d: Add support for stream transport for debugging purposes +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-notifications-node@0.2.4-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration-aws-node@0.1.12 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + +## 0.2.0-next.1 + +### Minor Changes + +- def53a7: **BREAKING** Following `NotificationTemplateRenderer` methods now return a Promise and **must** be awaited: `getSubject`, `getText` and `getHtml`. + + Required changes and example usage: + + ```diff + import { notificationsEmailTemplateExtensionPoint } from '@backstage/plugin-notifications-backend-module-email'; + import { Notification } from '@backstage/plugin-notifications-common'; + +import { getNotificationSubject, getNotificationTextContent, getNotificationHtmlContent } from 'my-notification-processing-library` + export const notificationsModuleEmailDecorator = createBackendModule({ + pluginId: 'notifications', + moduleId: 'email.templates', + register(reg) { + reg.registerInit({ + deps: { + emailTemplates: notificationsEmailTemplateExtensionPoint, + }, + async init({ emailTemplates }) { + emailTemplates.setTemplateRenderer({ + - getSubject(notification) { + + async getSubject(notification) { + - return `New notification from ${notification.source}`; + + const subject = await getNotificationSubject(notification); + + return `New notification from ${subject}`; + }, + - getText(notification) { + + async getText(notification) { + - return notification.content; + + const text = await getNotificationTextContent(notification); + + return text; + }, + - getHtml(notification) { + + async getHtml(notification) { + - return `

${notification.content}

`; + + const html = await getNotificationHtmlContent(notification); + + return html; + }, + }); + }, + }); + }, + }); + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration-aws-node@0.1.12 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.1 + +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + +## 0.1.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.1.3-next.1 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/README.md b/plugins/notifications-backend-module-email/README.md index 7bbac05b62..1defad74b4 100644 --- a/plugins/notifications-backend-module-email/README.md +++ b/plugins/notifications-backend-module-email/README.md @@ -2,7 +2,7 @@ Adds support for sending Backstage notifications as emails to users. -Supports sending emails using `SMTP`, `SES`, or `sendmail`. +Supports sending emails using `SMTP`, `SES`, `sendmail`, or `stream` (for debugging purposes). ## Customizing email content diff --git a/plugins/notifications-backend-module-email/api-report.md b/plugins/notifications-backend-module-email/api-report.md index 7e8eac6cb7..b105f15cba 100644 --- a/plugins/notifications-backend-module-email/api-report.md +++ b/plugins/notifications-backend-module-email/api-report.md @@ -23,10 +23,10 @@ export default notificationsModuleEmail; // @public (undocumented) export interface NotificationTemplateRenderer { // (undocumented) - getHtml?(notification: Notification_2): string; + getHtml?(notification: Notification_2): Promise; // (undocumented) - getSubject?(notification: Notification_2): string; + getSubject?(notification: Notification_2): Promise; // (undocumented) - getText?(notification: Notification_2): string; + getText?(notification: Notification_2): Promise; } ``` diff --git a/plugins/notifications-backend-module-email/config.d.ts b/plugins/notifications-backend-module-email/config.d.ts index 92f3385d1b..56a238d0dd 100644 --- a/plugins/notifications-backend-module-email/config.d.ts +++ b/plugins/notifications-backend-module-email/config.d.ts @@ -79,6 +79,10 @@ export interface Config { * Newline style, defaults to 'unix' */ newline?: 'unix' | 'windows'; + } + | { + /** Only for debugging, disables the actual sending of emails */ + transport: 'stream'; }; /** * Sender email address diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index c47a65d4f4..33451341ea 100644 --- a/plugins/notifications-backend-module-email/package.json +++ b/plugins/notifications-backend-module-email/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-email", - "version": "0.1.3-next.1", + "version": "0.2.0-next.2", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend-module-email/src/extensions.ts b/plugins/notifications-backend-module-email/src/extensions.ts index 454fe9b384..49795eadcf 100644 --- a/plugins/notifications-backend-module-email/src/extensions.ts +++ b/plugins/notifications-backend-module-email/src/extensions.ts @@ -20,9 +20,9 @@ import { Notification } from '@backstage/plugin-notifications-common'; * @public */ export interface NotificationTemplateRenderer { - getSubject?(notification: Notification): string; - getText?(notification: Notification): string; - getHtml?(notification: Notification): string; + getSubject?(notification: Notification): Promise; + getText?(notification: Notification): Promise; + getHtml?(notification: Notification): Promise; } /** diff --git a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts index 8689afc065..dee139e0de 100644 --- a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts +++ b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts @@ -37,6 +37,7 @@ import { createSendmailTransport, createSesTransport, createSmtpTransport, + createStreamTransport, } from './transports'; import { UserEntity } from '@backstage/catalog-model'; import { compact } from 'lodash'; @@ -105,6 +106,8 @@ export class NotificationsEmailProcessor implements NotificationProcessor { ); } else if (transport === 'sendmail') { this.transporter = createSendmailTransport(this.transportConfig); + } else if (transport === 'stream') { + this.transporter = createStreamTransport(); } else { throw new Error(`Unsupported transport: ${transport}`); } @@ -205,6 +208,7 @@ export class NotificationsEmailProcessor implements NotificationProcessor { private async sendMail(options: Mail.Options) { try { + this.logger.debug(`Sending notification email to ${options.to}`); await this.transporter.sendMail(options); } catch (e) { this.logger.error(`Failed to send email to ${options.to}: ${e}`); @@ -280,10 +284,10 @@ export class NotificationsEmailProcessor implements NotificationProcessor { const mailOptions = { from: this.sender, subject: - this.templateRenderer?.getSubject?.(notification) ?? + (await this.templateRenderer?.getSubject?.(notification)) ?? notification.payload.title, - html: this.templateRenderer?.getHtml?.(notification), - text: this.templateRenderer?.getText?.(notification), + html: await this.templateRenderer?.getHtml?.(notification), + text: await this.templateRenderer?.getText?.(notification), replyTo: this.replyTo, }; diff --git a/plugins/notifications-backend-module-email/src/processor/transports/index.ts b/plugins/notifications-backend-module-email/src/processor/transports/index.ts index ccea9f77cc..9a679f3723 100644 --- a/plugins/notifications-backend-module-email/src/processor/transports/index.ts +++ b/plugins/notifications-backend-module-email/src/processor/transports/index.ts @@ -16,3 +16,4 @@ export { createSmtpTransport } from './smtp'; export { createSesTransport } from './ses'; export { createSendmailTransport } from './sendmail'; +export { createStreamTransport } from './stream'; diff --git a/plugins/notifications-backend-module-email/src/processor/transports/stream.ts b/plugins/notifications-backend-module-email/src/processor/transports/stream.ts new file mode 100644 index 0000000000..26ed401366 --- /dev/null +++ b/plugins/notifications-backend-module-email/src/processor/transports/stream.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. + */ +import { createTransport } from 'nodemailer'; + +export const createStreamTransport = () => { + return createTransport({ streamTransport: true }); +}; diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index a4be935628..61cba9e3a6 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,75 @@ # @backstage/plugin-notifications-backend +## 0.3.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-notifications-node@0.2.4-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-events-node@0.3.9-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @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.5 + +## 0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-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.18-next.1 + - @backstage/plugin-events-node@0.3.9-next.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.1 + - @backstage/plugin-signals-node@0.1.9-next.1 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## 0.3.3 + +### Patch Changes + +- d7b8ca5: Added an option to filter notifications by topic +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.3.3-next.1 ### Patch Changes diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index bfa1f2f0bd..9bc26f7a1f 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.3.3-next.1", + "version": "0.3.4-next.2", "backstage": { "role": "backend-plugin", "pluginId": "notifications", @@ -52,7 +52,7 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "knex": "^3.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0", "winston": "^3.2.1", "yn": "^4.0.0" diff --git a/plugins/notifications-common/CHANGELOG.md b/plugins/notifications-common/CHANGELOG.md index 17231f0147..6e10272c36 100644 --- a/plugins/notifications-common/CHANGELOG.md +++ b/plugins/notifications-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-notifications-common +## 0.0.5 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/config@1.2.0 + ## 0.0.4 ### Patch Changes diff --git a/plugins/notifications-common/package.json b/plugins/notifications-common/package.json index 3802d6535c..139681e6c6 100644 --- a/plugins/notifications-common/package.json +++ b/plugins/notifications-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-common", - "version": "0.0.4", + "version": "0.0.5", "description": "Common functionalities for the notifications plugin", "backstage": { "role": "common-library", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index 69e594b513..627cb53ea0 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-notifications-node +## 0.2.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.9-next.1 + +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## 0.2.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/notifications-node/api-report.md b/plugins/notifications-node/api-report.md index 37f28fec35..995b98bc21 100644 --- a/plugins/notifications-node/api-report.md +++ b/plugins/notifications-node/api-report.md @@ -65,7 +65,11 @@ export interface NotificationService { } // @public (undocumented) -export const notificationService: ServiceRef; +export const notificationService: ServiceRef< + NotificationService, + 'plugin', + 'singleton' +>; // @public (undocumented) export type NotificationServiceOptions = { diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index f18ce420f7..533ebe7ce2 100644 --- a/plugins/notifications-node/package.json +++ b/plugins/notifications-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-node", - "version": "0.2.3-next.1", + "version": "0.2.4-next.2", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", @@ -44,7 +44,7 @@ "@backstage/plugin-notifications-common": "workspace:^", "@backstage/plugin-signals-node": "workspace:^", "knex": "^3.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/plugins/notifications-node/src/service/DefaultNotificationService.test.ts b/plugins/notifications-node/src/service/DefaultNotificationService.test.ts index d5c327e788..3872f898ee 100644 --- a/plugins/notifications-node/src/service/DefaultNotificationService.test.ts +++ b/plugins/notifications-node/src/service/DefaultNotificationService.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { NotificationPayload } from '@backstage/plugin-notifications-common'; @@ -32,7 +32,7 @@ const testNotification: NotificationPayload = { describe('DefaultNotificationService', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); const discovery = mockServices.discovery.mock({ getBaseUrl: jest.fn().mockResolvedValue('http://example.com'), diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index 97e6c50b44..42c55615b2 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-notifications +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-react@0.0.4 + +## 0.2.3 + +### Patch Changes + +- 3bf0697: The toolbar on the Notifications page is hidden when there are no listed notifications. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + ## 0.2.3-next.2 ### Patch Changes diff --git a/plugins/notifications/api-report.md b/plugins/notifications/api-report.md index 9240bdb1c2..5e06ae2616 100644 --- a/plugins/notifications/api-report.md +++ b/plugins/notifications/api-report.md @@ -176,20 +176,5 @@ export function useNotificationsApi( value: T; }; -// @public (undocumented) -export function useTitleCounter(): { - setNotificationCount: (newCount: number) => void; -}; - -// @public (undocumented) -export function useWebNotifications(enabled: boolean): { - sendWebNotification: (options: { - id: string; - title: string; - description: string; - link?: string; - }) => Notification | null; -}; - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 4ef28f9508..5dbfd83255 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.2.3-next.2", + "version": "0.2.4-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications/src/api/NotificationsClient.test.ts b/plugins/notifications/src/api/NotificationsClient.test.ts index e9acd04fc9..f378269e45 100644 --- a/plugins/notifications/src/api/NotificationsClient.test.ts +++ b/plugins/notifications/src/api/NotificationsClient.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { NotificationsClient } from './NotificationsClient'; @@ -33,7 +33,7 @@ const testNotification: Partial = { }; describe('NotificationsClient', () => { - setupRequestMockHandlers(server); + registerMswTestHooks(server); const mockBaseUrl = 'http://backstage/api/notifications'; const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; const fetchApi = new MockFetchApi(); diff --git a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx index 7b55c63747..457893b016 100644 --- a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx +++ b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx @@ -114,7 +114,9 @@ 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, requestUserPermission } = useWebNotifications( + webNotificationsEnabled, + ); const [refresh, setRefresh] = React.useState(false); const { setNotificationCount } = useTitleCounter(); @@ -126,6 +128,19 @@ export const NotificationsSidebarItem = (props?: { component={Link} to={notification.payload.link ?? notificationsRoute()} onClick={() => { + if (notification.payload.link) { + notificationsApi + .updateNotifications({ + ids: [notification.id], + read: true, + }) + .catch(() => { + alertApi.post({ + message: 'Failed to mark notification as read', + severity: 'error', + }); + }); + } closeSnackbar(snackBarId); }} > @@ -259,6 +274,9 @@ export const NotificationsSidebarItem = (props?: { )} { + requestUserPermission(); + }} hasNotifications={!error && !!unreadCount} text={text} icon={icon} 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 728d992130..ec120a614d 100644 --- a/plugins/notifications/src/hooks/useWebNotifications.ts +++ b/plugins/notifications/src/hooks/useWebNotifications.ts @@ -13,19 +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 { 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 */ +/** @internal */ 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 && @@ -57,6 +59,10 @@ export function useWebNotifications(enabled: boolean) { event.preventDefault(); if (options.link) { window.open(options.link, '_blank'); + notificationsApi.updateNotifications({ + ids: [options.id], + read: true, + }); } else { navigate(notificationsRoute()); } @@ -65,8 +71,8 @@ export function useWebNotifications(enabled: boolean) { return notification; }, - [webNotificationPermission, navigate, notificationsRoute], + [webNotificationPermission, notificationsApi, navigate, notificationsRoute], ); - return { sendWebNotification }; + return { sendWebNotification, requestUserPermission }; } 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'; diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index d13578fd32..4bbf343849 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-org-react +## 0.1.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.26-next.2 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index e6494eaa28..d91d73c4ca 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.26-next.2", + "version": "0.1.27-next.2", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index aa4bd9a93f..923d5d1d23 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-org +## 0.6.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-catalog-common@1.0.26-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.6.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/plugin-catalog-common@1.0.26-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.6.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-catalog-common@1.0.25 + +## 0.6.27 + +### Patch Changes + +- 5132d28: The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. +- c307ef4: Added `relationType` property to EntityMembersListCard component that allows for display users related to a group via some other relationship aside from `memberOf`. + + Also, as a side effect, the `relationsType` property has been deprecated in favor of a more accurately named `relationAggregation` property. + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + ## 0.6.27-next.2 ### Patch Changes diff --git a/plugins/org/api-report-alpha.md b/plugins/org/api-report-alpha.md index 8c5391d857..e7c4db2c6d 100644 --- a/plugins/org/api-report-alpha.md +++ b/plugins/org/api-report-alpha.md @@ -10,7 +10,7 @@ import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; const _default: BackstagePlugin< {}, { - catalogIndex: ExternalRouteRef; + catalogIndex: ExternalRouteRef; } >; export default _default; diff --git a/plugins/org/package.json b/plugins/org/package.json index c2d43bc5ed..44ae3d10f6 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.27-next.2", + "version": "0.6.28-next.2", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index 616c6acda2..7c0765ad43 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + +## 0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## 0.1.19 + +### Patch Changes + +- ed10fd2: Internal refactor to use new `PolicyQueryUser` type. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.19-next.1 ### Patch Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index 60e11825f4..0ba16a61f7 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", - "version": "0.1.19-next.1", + "version": "0.1.20-next.2", "description": "Allow all policy backend module for the permission plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/permission-backend-module-policy-allow-all/src/policy.ts b/plugins/permission-backend-module-policy-allow-all/src/policy.ts index da853e47db..90ae21f341 100644 --- a/plugins/permission-backend-module-policy-allow-all/src/policy.ts +++ b/plugins/permission-backend-module-policy-allow-all/src/policy.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { AuthorizeResult, PolicyDecision, @@ -22,12 +21,13 @@ import { import { PermissionPolicy, PolicyQuery, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; export class AllowAllPermissionPolicy implements PermissionPolicy { async handle( _request: PolicyQuery, - _user?: BackstageIdentityResponse, + _user?: PolicyQueryUser, ): Promise { return { result: AuthorizeResult.ALLOW, diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 39ae10e557..89955c0f69 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,65 @@ # @backstage/plugin-permission-backend +## 0.5.47-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.5.47-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 0.5.47-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## 0.5.46 + +### Patch Changes + +- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + + - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. + - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + + Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.5.46-next.1 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 43a57407e1..7a331c1ccd 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.5.46-next.1", + "version": "0.5.47-next.2", "backstage": { "role": "backend-plugin", "pluginId": "permission", @@ -63,7 +63,7 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "lodash": "^4.17.21", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "yn": "^4.0.0", "zod": "^3.22.4" }, diff --git a/plugins/permission-backend/src/service/router.test.ts b/plugins/permission-backend/src/service/router.test.ts index be90c5f628..f12bacc61d 100644 --- a/plugins/permission-backend/src/service/router.test.ts +++ b/plugins/permission-backend/src/service/router.test.ts @@ -186,6 +186,13 @@ describe('createRouter', () => { mockCredentials.user().principal.userEntityRef, ], }, + info: { + userEntityRef: mockCredentials.user().principal.userEntityRef, + ownershipEntityRefs: [ + mockCredentials.user().principal.userEntityRef, + ], + }, + credentials: mockCredentials.user(), }, ); expect(response.body).toEqual({ diff --git a/plugins/permission-backend/src/service/router.ts b/plugins/permission-backend/src/service/router.ts index cc45d0b41a..fd33f0b629 100644 --- a/plugins/permission-backend/src/service/router.ts +++ b/plugins/permission-backend/src/service/router.ts @@ -22,10 +22,7 @@ import { errorHandler, } from '@backstage/backend-common'; import { InputError } from '@backstage/errors'; -import { - BackstageIdentityResponse, - IdentityApi, -} from '@backstage/plugin-auth-node'; +import { IdentityApi } from '@backstage/plugin-auth-node'; import { AuthorizeResult, EvaluatePermissionRequest, @@ -40,6 +37,7 @@ import { ApplyConditionsRequestEntry, ApplyConditionsResponseEntry, PermissionPolicy, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; import { PermissionIntegrationClient } from './PermissionIntegrationClient'; import { memoize } from 'lodash'; @@ -130,9 +128,9 @@ const handleRequest = async ( ); }); - let user: BackstageIdentityResponse | undefined; + let user: PolicyQueryUser | undefined; if (auth.isPrincipal(credentials, 'user')) { - const { ownershipEntityRefs } = await userInfo.getUserInfo(credentials); + const info = await userInfo.getUserInfo(credentials); const { token } = await auth.getPluginRequestToken({ onBehalfOf: credentials, targetPluginId: 'catalog', // TODO: unknown at this point @@ -141,9 +139,11 @@ const handleRequest = async ( identity: { type: 'user', userEntityRef: credentials.principal.userEntityRef, - ownershipEntityRefs, + ownershipEntityRefs: info.ownershipEntityRefs, }, token, + credentials, + info, }; } diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index e6b637a092..8ef1eb314f 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-permission-common +## 0.8.1-next.1 + +### Patch Changes + +- df784fe: Add the MetadataResponse type from @backstage/plugin-permission-node, since this + type might be used in frontend code. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.8.1-next.0 + +### Patch Changes + +- 137fa34: Add the MetadataResponseSerializedRule type from @backstage/plugin-permission-node, since this type might be used in frontend code. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.8.0 + +### Minor Changes + +- f4085b8: **BREAKING**: Removed the deprecated and unused `token` option from `EvaluatorRequestOptions`. The `PermissionsClient` now has its own `PermissionClientRequestOptions` type that declares the `token` option instead. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.7.14 ### Patch Changes diff --git a/plugins/permission-common/api-report.md b/plugins/permission-common/api-report.md index 1c2476d20d..465c43846f 100644 --- a/plugins/permission-common/api-report.md +++ b/plugins/permission-common/api-report.md @@ -5,6 +5,7 @@ ```ts import { Config } from '@backstage/config'; import { JsonPrimitive } from '@backstage/types'; +import zodToJsonSchema from 'zod-to-json-schema'; // @public export type AllOfCriteria = { @@ -94,9 +95,7 @@ export type EvaluatePermissionResponseBatch = PermissionMessageBatch; // @public -export type EvaluatorRequestOptions = { - token?: string; -}; +export interface EvaluatorRequestOptions {} // @public export type IdentifiedPermissionMessage = T & { @@ -127,6 +126,20 @@ export function isResourcePermission( // @public export function isUpdatePermission(permission: Permission): boolean; +// @public +export type MetadataResponse = { + permissions?: Permission[]; + rules: MetadataResponseSerializedRule[]; +}; + +// @public +export type MetadataResponseSerializedRule = { + name: string; + description: string; + resourceType: string; + paramsSchema?: ReturnType; +}; + // @public export type NotCriteria = { not: PermissionCriteria; @@ -162,14 +175,19 @@ export class PermissionClient implements PermissionEvaluator { constructor(options: { discovery: DiscoveryApi; config: Config }); authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise; authorizeConditional( queries: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise; } +// @public +export type PermissionClientRequestOptions = { + token?: string; +}; + // @public export type PermissionCondition< TResourceType extends string = string, @@ -191,11 +209,15 @@ export type PermissionCriteria = export interface PermissionEvaluator { authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { + _ignored?: never; + }, ): Promise; authorizeConditional( requests: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { + _ignored?: never; + }, ): Promise; } diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index ee54459589..faeaf4a972 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-common", - "version": "0.7.14", + "version": "0.8.1-next.1", "description": "Isomorphic types and client for Backstage permissions and authorization", "backstage": { "role": "common-library", @@ -53,7 +53,8 @@ "@backstage/types": "workspace:^", "cross-fetch": "^4.0.0", "uuid": "^9.0.0", - "zod": "^3.22.4" + "zod": "^3.22.4", + "zod-to-json-schema": "^3.20.4" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/permission-common/src/PermissionClient.ts b/plugins/permission-common/src/PermissionClient.ts index a5d08205d8..2414774775 100644 --- a/plugins/permission-common/src/PermissionClient.ts +++ b/plugins/permission-common/src/PermissionClient.ts @@ -27,7 +27,6 @@ import { PermissionEvaluator, QueryPermissionRequest, AuthorizePermissionRequest, - EvaluatorRequestOptions, AuthorizePermissionResponse, QueryPermissionResponse, } from './types/api'; @@ -93,6 +92,15 @@ const responseSchema = ( ), }); +/** + * Options for {@link PermissionClient} requests. + * + * @public + */ +export type PermissionClientRequestOptions = { + token?: string; +}; + /** * An isomorphic client for requesting authorization for Backstage permissions. * @public @@ -112,7 +120,7 @@ export class PermissionClient implements PermissionEvaluator { */ async authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise { return this.makeRequest( requests, @@ -126,7 +134,7 @@ export class PermissionClient implements PermissionEvaluator { */ async authorizeConditional( queries: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise { return this.makeRequest(queries, queryPermissionResponseSchema, options); } diff --git a/plugins/permission-common/src/types/api.ts b/plugins/permission-common/src/types/api.ts index e597384a56..072615989b 100644 --- a/plugins/permission-common/src/types/api.ts +++ b/plugins/permission-common/src/types/api.ts @@ -244,7 +244,7 @@ export interface PermissionEvaluator { */ authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { _ignored?: never }, // Since the options are empty we add this placeholder to reject all options ): Promise; /** @@ -257,22 +257,20 @@ export interface PermissionEvaluator { */ authorizeConditional( requests: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { _ignored?: never }, // Since the options are empty we add this placeholder to reject all options ): Promise; } +// Note(Rugvip): I kept the below type around in case we want to add new options +// in the future, for example a signal. It also helps out enabling API +// constraints, as without this we can't have the permissions service implement +// the evaluator interface due to the mismatch in parameter count. + /** * Options for {@link PermissionEvaluator} requests. * + * This is currently empty, as there are no longer any common options for the permission evaluator. + * * @public */ -export type EvaluatorRequestOptions = { - /** - * @deprecated Backend plugins should no longer depend on the - * `PermissionEvaluator`, but instead use the `PermissionService` from - * `@backstage/backend-plugin-api`. Frontend plugins should not need to inject - * this token at all, but instead implicitly rely on underlying fetchApi to do - * it for them. - */ - token?: string; -}; +export interface EvaluatorRequestOptions {} diff --git a/plugins/permission-common/src/types/index.ts b/plugins/permission-common/src/types/index.ts index 5702f47c1c..f5380541df 100644 --- a/plugins/permission-common/src/types/index.ts +++ b/plugins/permission-common/src/types/index.ts @@ -40,6 +40,10 @@ export type { NotCriteria, } from './api'; export type { DiscoveryApi } from './discovery'; +export type { + MetadataResponse, + MetadataResponseSerializedRule, +} from './integration'; export type { BasicPermission, PermissionAttributes, diff --git a/plugins/permission-common/src/types/integration.ts b/plugins/permission-common/src/types/integration.ts new file mode 100644 index 0000000000..d531140923 --- /dev/null +++ b/plugins/permission-common/src/types/integration.ts @@ -0,0 +1,42 @@ +/* + * 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 zodToJsonSchema from 'zod-to-json-schema'; +import { Permission } from './permission'; + +/** + * Serialized permission rules, with the paramsSchema + * converted from a ZodSchema to a JsonSchema. + * + * @public + */ +export type MetadataResponseSerializedRule = { + name: string; + description: string; + resourceType: string; + paramsSchema?: ReturnType; +}; + +/** + * Response type for the .metadata endpoint in + * {@link @backstage/plugin-permission-node#createPermissionIntegrationRouter} + * + * @public + */ +export type MetadataResponse = { + permissions?: Permission[]; + rules: MetadataResponseSerializedRule[]; +}; diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index a63abb1d95..282ea5fda8 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,71 @@ # @backstage/plugin-permission-node +## 0.8.1-next.2 + +### Patch Changes + +- df784fe: The MetadataResponse type has been moved to @backstage/plugin-permission-common + to match the recent move of MetadataResponseSerializedRule, and should be + imported from there going forward. To avoid an immediate breaking change, this + type is still re-exported from this package, but is marked as deprecated and + will be removed in a future release. +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.8.1-next.1 + +### Patch Changes + +- 5cd9878: The MetadataResponseSerializedRule type has been moved to @backstage/plugin-permission-common, and should be imported from there going forward. To avoid an immediate breaking change, this type is still re-exported from this package, but is marked as deprecated and will be removed in a future release. +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.1 + +## 0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## 0.8.0 + +### Minor Changes + +- 36f91e8: **BREAKING**: Updated the `ServerPermissionClient` to match the new `PermissionsService` interface, where the deprecated `token` option has been removed and the options are now required. + +### Patch Changes + +- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + + - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. + - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + + Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +- 28b2cfb: Fix invalid cross-reference in API Reference docs +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.7.33-next.1 ### Patch Changes diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index 290c586f2c..36483bd342 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -8,13 +8,17 @@ import { AnyOfCriteria } from '@backstage/plugin-permission-common'; import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common'; import { AuthorizePermissionResponse } from '@backstage/plugin-permission-common'; import { AuthService } from '@backstage/backend-plugin-api'; -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { BackstageUserIdentity } from '@backstage/plugin-auth-node'; +import { BackstageUserInfo } from '@backstage/backend-plugin-api'; import { ConditionalPolicyDecision } from '@backstage/plugin-permission-common'; import { Config } from '@backstage/config'; import { DefinitivePolicyDecision } from '@backstage/plugin-permission-common'; import { DiscoveryService } from '@backstage/backend-plugin-api'; import express from 'express'; import { IdentifiedPermissionMessage } from '@backstage/plugin-permission-common'; +import { MetadataResponse as MetadataResponse_2 } from '@backstage/plugin-permission-common'; +import { MetadataResponseSerializedRule as MetadataResponseSerializedRule_2 } from '@backstage/plugin-permission-common'; import { NotCriteria } from '@backstage/plugin-permission-common'; import { Permission } from '@backstage/plugin-permission-common'; import { PermissionCondition } from '@backstage/plugin-permission-common'; @@ -27,7 +31,6 @@ import { QueryPermissionRequest } from '@backstage/plugin-permission-common'; import { ResourcePermission } from '@backstage/plugin-permission-common'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { z } from 'zod'; -import zodToJsonSchema from 'zod-to-json-schema'; // @public export type ApplyConditionsRequest = { @@ -186,19 +189,11 @@ export const makeCreatePermissionRule: < rule: PermissionRule, ) => PermissionRule; -// @public -export type MetadataResponse = { - permissions?: Permission[]; - rules: MetadataResponseSerializedRule[]; -}; +// @public @deprecated +export type MetadataResponse = MetadataResponse_2; -// @public -export type MetadataResponseSerializedRule = { - name: string; - description: string; - resourceType: string; - paramsSchema?: ReturnType; -}; +// @public @deprecated +export type MetadataResponseSerializedRule = MetadataResponseSerializedRule_2; // @public export type PermissionIntegrationRouterOptions< @@ -246,10 +241,7 @@ export type PermissionIntegrationRouterOptions< // @public export interface PermissionPolicy { // (undocumented) - handle( - request: PolicyQuery, - user?: BackstageIdentityResponse, - ): Promise; + handle(request: PolicyQuery, user?: PolicyQueryUser): Promise; } // @public @@ -272,6 +264,15 @@ export type PolicyQuery = { permission: Permission; }; +// @public +export type PolicyQueryUser = { + token: string; + expiresInSeconds?: number; + identity: BackstageUserIdentity; + credentials: BackstageCredentials; + info: BackstageUserInfo; +}; + // @public export class ServerPermissionClient implements PermissionsService { // (undocumented) diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index db3c067088..b2c2d06f11 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.7.33-next.1", + "version": "0.8.1-next.2", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/permission-node/src/ServerPermissionClient.test.ts b/plugins/permission-node/src/ServerPermissionClient.test.ts index 6e99ff71ab..5c6328ae44 100644 --- a/plugins/permission-node/src/ServerPermissionClient.test.ts +++ b/plugins/permission-node/src/ServerPermissionClient.test.ts @@ -25,7 +25,7 @@ import { import { mockCredentials, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { setupServer } from 'msw/node'; @@ -54,7 +54,7 @@ const config = new ConfigReader({ }); describe('ServerPermissionClient', () => { - setupRequestMockHandlers(server); + registerMswTestHooks(server); const discovery = mockServices.discovery.mock(); @@ -83,18 +83,22 @@ describe('ServerPermissionClient', () => { const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { discovery, tokenManager: mockServices.tokenManager.mock(), + auth: mockServices.auth(), }); - await client.authorize([ - { - permission: testBasicPermission, - }, - ]); + await client.authorize( + [ + { + permission: testBasicPermission, + }, + ], + { credentials: mockCredentials.none() }, + ); expect(mockAuthorizeHandler).not.toHaveBeenCalled(); }); - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { + it('should bypass the permission backend if permissions are enabled and request has valid server credentials', async () => { const client = ServerPermissionClient.fromConfig(config, { discovery, tokenManager: mockServices.tokenManager.mock(), @@ -102,13 +106,13 @@ describe('ServerPermissionClient', () => { }); await client.authorize([{ permission: testBasicPermission }], { - token: mockCredentials.service.token(), + credentials: mockCredentials.service(), }); expect(mockAuthorizeHandler).not.toHaveBeenCalled(); }); - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { + it('should call the permission backend if permissions are enabled and request does not have valid server credentials', async () => { const client = ServerPermissionClient.fromConfig(config, { discovery, tokenManager: mockServices.tokenManager.mock(), @@ -116,10 +120,18 @@ describe('ServerPermissionClient', () => { }); await client.authorize([{ permission: testBasicPermission }], { - token: mockCredentials.user.token(), + credentials: mockCredentials.user(), }); expect(mockAuthorizeHandler).toHaveBeenCalled(); + expect( + mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), + ).toBe( + mockCredentials.service.header({ + onBehalfOf: mockCredentials.user(), + targetPluginId: 'permission', + }), + ); }); }); @@ -145,201 +157,59 @@ describe('ServerPermissionClient', () => { const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { discovery, tokenManager: mockServices.tokenManager.mock(), - }); - - await client.authorizeConditional([ - { permission: testResourcePermission }, - ]); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), + auth: mockServices.auth(), }); await client.authorizeConditional( [{ permission: testResourcePermission }], { - token: mockCredentials.service.token(), + credentials: mockCredentials.none(), }, ); expect(mockAuthorizeHandler).not.toHaveBeenCalled(); }); - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { - const auth = mockServices.auth(); + it('should bypass the permission backend if permissions are enabled and request has valid server credentials', async () => { const client = ServerPermissionClient.fromConfig(config, { discovery, tokenManager: mockServices.tokenManager.mock(), - auth, + auth: mockServices.auth(), }); await client.authorizeConditional( [{ permission: testResourcePermission }], { - token: mockCredentials.user.token(), + credentials: mockCredentials.service(), + }, + ); + + expect(mockAuthorizeHandler).not.toHaveBeenCalled(); + }); + + it('should call the permission backend if permissions are enabled and request does not have valid server credentials', async () => { + const client = ServerPermissionClient.fromConfig(config, { + discovery, + tokenManager: mockServices.tokenManager.mock(), + auth: mockServices.auth(), + }); + + await client.authorizeConditional( + [{ permission: testResourcePermission }], + { + credentials: mockCredentials.user(), }, ); expect(mockAuthorizeHandler).toHaveBeenCalled(); - }); - }); - - describe('with credentials', () => { - describe('authorize', () => { - let mockAuthorizeHandler: jest.Mock; - - beforeEach(() => { - mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => { - const responses = req.body.items.map( - (r: IdentifiedPermissionMessage) => ({ - id: r.id, - result: AuthorizeResult.ALLOW, - }), - ); - - return res(json({ items: responses })); - }); - - server.use(rest.post(`${mockBaseUrl}/authorize`, mockAuthorizeHandler)); - }); - - it('should bypass the permission backend if permissions are disabled', async () => { - const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorize( - [ - { - permission: testBasicPermission, - }, - ], - { credentials: mockCredentials.none() }, - ); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorize([{ permission: testBasicPermission }], { - credentials: mockCredentials.service(), - }); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorize([{ permission: testBasicPermission }], { - credentials: mockCredentials.user(), - }); - - expect(mockAuthorizeHandler).toHaveBeenCalled(); - expect( - mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), - ).toBe( - mockCredentials.service.header({ - onBehalfOf: mockCredentials.user(), - targetPluginId: 'permission', - }), - ); - }); - }); - - describe('authorizeConditional', () => { - let mockAuthorizeHandler: jest.Mock; - - beforeEach(() => { - mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => { - const responses = req.body.items.map( - (r: IdentifiedPermissionMessage) => ({ - id: r.id, - result: AuthorizeResult.ALLOW, - }), - ); - - return res(json({ items: responses })); - }); - - server.use(rest.post(`${mockBaseUrl}/authorize`, mockAuthorizeHandler)); - }); - - it('should bypass the permission backend if permissions are disabled', async () => { - const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorizeConditional( - [{ permission: testResourcePermission }], - { - credentials: mockCredentials.none(), - }, - ); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorizeConditional( - [{ permission: testResourcePermission }], - { - credentials: mockCredentials.service(), - }, - ); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorizeConditional( - [{ permission: testResourcePermission }], - { - credentials: mockCredentials.user(), - }, - ); - - expect(mockAuthorizeHandler).toHaveBeenCalled(); - expect( - mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), - ).toBe( - mockCredentials.service.header({ - onBehalfOf: mockCredentials.user(), - targetPluginId: 'permission', - }), - ); - }); + expect( + mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), + ).toBe( + mockCredentials.service.header({ + onBehalfOf: mockCredentials.user(), + targetPluginId: 'permission', + }), + ); }); }); diff --git a/plugins/permission-node/src/ServerPermissionClient.ts b/plugins/permission-node/src/ServerPermissionClient.ts index cf54f3b894..e21067bfa1 100644 --- a/plugins/permission-node/src/ServerPermissionClient.ts +++ b/plugins/permission-node/src/ServerPermissionClient.ts @@ -146,14 +146,6 @@ export class ServerPermissionClient implements PermissionsService { return options.credentials; } - if (options?.token) { - try { - return await this.#auth.authenticate(options.token); - } catch { - // ignore - } - } - return undefined; } diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 4a52c33f18..40d215d515 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -24,6 +24,8 @@ import { AuthorizeResult, DefinitivePolicyDecision, IdentifiedPermissionMessage, + MetadataResponse as CommonMetadataResponse, + MetadataResponseSerializedRule as CommonMetadataResponseSerializedRule, Permission, PermissionCondition, PermissionCriteria, @@ -109,23 +111,18 @@ export type ApplyConditionsResponse = { * converted from a ZodSchema to a JsonSchema. * * @public + * @deprecated Please import from `@backstage/plugin-permission-common` instead. */ -export type MetadataResponseSerializedRule = { - name: string; - description: string; - resourceType: string; - paramsSchema?: ReturnType; -}; +export type MetadataResponseSerializedRule = + CommonMetadataResponseSerializedRule; /** * Response type for the .metadata endpoint. * * @public + * @deprecated Please import from `@backstage/plugin-permission-common` instead. */ -export type MetadataResponse = { - permissions?: Permission[]; - rules: MetadataResponseSerializedRule[]; -}; +export type MetadataResponse = CommonMetadataResponse; const applyConditions = ( criteria: PermissionCriteria>, diff --git a/plugins/permission-node/src/policy/index.ts b/plugins/permission-node/src/policy/index.ts index f151cfb4fb..fd47ed7e62 100644 --- a/plugins/permission-node/src/policy/index.ts +++ b/plugins/permission-node/src/policy/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export type { PermissionPolicy, PolicyQuery } from './types'; +export type { PermissionPolicy, PolicyQuery, PolicyQueryUser } from './types'; diff --git a/plugins/permission-node/src/policy/types.ts b/plugins/permission-node/src/policy/types.ts index 0f469cfbfe..a7b8b75218 100644 --- a/plugins/permission-node/src/policy/types.ts +++ b/plugins/permission-node/src/policy/types.ts @@ -18,7 +18,11 @@ import { Permission, PolicyDecision, } from '@backstage/plugin-permission-common'; -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { BackstageUserIdentity } from '@backstage/plugin-auth-node'; +import { + BackstageCredentials, + BackstageUserInfo, +} from '@backstage/backend-plugin-api'; /** * A query to be evaluated by the {@link PermissionPolicy}. @@ -34,6 +38,44 @@ export type PolicyQuery = { permission: Permission; }; +/** + * The context within which a policy query is evaluated. + * + * @public + */ +export type PolicyQueryUser = { + /** + * The token used to authenticate the user within Backstage. + * + * @deprecated User the `credentials` field in combination with `coreServices.auth` to generate a request token instead. + */ + token: string; + + /** + * The number of seconds until the token expires. If not set, it can be assumed that the token does not expire. + * + * @deprecated This field is deprecated and will be removed in a future release. + */ + expiresInSeconds?: number; + + /** + * A plaintext description of the identity that is encapsulated within the token. + * + * @deprecated Use the `info` field instead. + */ + identity: BackstageUserIdentity; + + /** + * The credentials of the user making the request. + */ + credentials: BackstageCredentials; + + /** + * The information for the user making the request. + */ + info: BackstageUserInfo; +}; + /** * A policy to evaluate authorization requests for any permissioned action performed in Backstage. * @@ -51,8 +93,5 @@ export type PolicyQuery = { * @public */ export interface PermissionPolicy { - handle( - request: PolicyQuery, - user?: BackstageIdentityResponse, - ): Promise; + handle(request: PolicyQuery, user?: PolicyQueryUser): Promise; } 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 * diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 1eb951e625..83f4dea7ed 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-permission-react +## 0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.4.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## 0.4.24 + +### Patch Changes + +- 28b2cfb: Improve API Reference documentation +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.4.23 ### Patch Changes diff --git a/plugins/permission-react/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/package.json b/plugins/permission-react/package.json index 9ebb13e633..394f56ff02 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.23", + "version": "0.4.25-next.1", "backstage": { "role": "web-library", "pluginId": "permission", 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'; diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index a6c1ef02d2..138b98902b 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-proxy-backend +## 0.5.4-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## 0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## 0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## 0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.5.3-next.1 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 23acc935f3..091e637886 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.5.3-next.1", + "version": "0.5.4-next.2", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", @@ -79,7 +79,7 @@ "@types/uuid": "^9.0.0", "@types/yup": "^0.32.0", "msw": "^2.0.0", - "node-fetch": "^2.6.7" + "node-fetch": "^2.7.0" }, "configSchema": "config.d.ts" } diff --git a/plugins/proxy-backend/src/service/router.config.test.ts b/plugins/proxy-backend/src/service/router.config.test.ts index ba81553a4f..be26ddb9bc 100644 --- a/plugins/proxy-backend/src/service/router.config.test.ts +++ b/plugins/proxy-backend/src/service/router.config.test.ts @@ -19,7 +19,7 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; import { - setupRequestMockHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { @@ -36,7 +36,7 @@ import fetch from 'node-fetch'; describe('createRouter reloadable configuration', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); it('should be able to observe the config', async () => { // Grab the subscriber function and use mutable config data to mock a config file change diff --git a/plugins/proxy-backend/src/service/router.credentials.test.ts b/plugins/proxy-backend/src/service/router.credentials.test.ts index 54c865ba11..ac32179ef3 100644 --- a/plugins/proxy-backend/src/service/router.credentials.test.ts +++ b/plugins/proxy-backend/src/service/router.credentials.test.ts @@ -20,7 +20,7 @@ import { } from '@backstage/backend-app-api'; import { mockServices, - setupRequestMockHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { ResponseError } from '@backstage/errors'; @@ -34,7 +34,7 @@ import fetch from 'node-fetch'; describe('credentials', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); it('handles all valid credentials settings', async () => { const config = { diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index c634d8c8ca..90541db310 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.1.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.14 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.14-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index c0e00e8ffe..92d64ec7f0 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", - "version": "0.1.14-next.1", + "version": "0.1.15-next.2", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index 4e1e2b9531..604b44d3da 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.1.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 3fca643: Added autocompletion support for resource `branches` +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.12 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index 5ce826ff1a..1806189dd4 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud", - "version": "0.1.12-next.1", + "version": "0.1.13-next.2", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -49,7 +49,7 @@ "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts index 5e95f41751..6b4b77879e 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketCloudAction } from './bitbucketCloud'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -66,7 +66,7 @@ describe('publish:bitbucketCloud', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts index 6a079a3f9b..6cac8a0e1c 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketCloudAction } from './bitbucketCloud'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -56,7 +56,7 @@ describe('publish:bitbucketCloud', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts index 472c7a6a03..3e306c4065 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts @@ -21,7 +21,7 @@ import yaml from 'yaml'; import { examples } from './bitbucketCloudPipelinesRun.examples'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; describe('bitbucket:pipelines:run', () => { @@ -48,7 +48,7 @@ describe('bitbucket:pipelines:run', () => { build_number: 1, }; const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts index 9386246868..edabe2a7ba 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts @@ -16,7 +16,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createBitbucketPipelinesRunAction } from './bitbucketCloudPipelinesRun'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; @@ -48,7 +48,7 @@ describe('bitbucket:pipelines:run', () => { build_number: 1, }; const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.clearAllMocks(); 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..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 @@ -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,19 @@ describe('handleAutocompleteRequest', () => { expect(result).toEqual({ results: [{ title: 'repository1' }] }); }); + it('should return branches', async () => { + const result = await handleAutocompleteRequest({ + token: 'foo', + resource: 'branches', + context: { + workspace: 'workspace1', + repository: 'repository1', + }, + }); + + expect(result).toEqual({ results: [{ title: 'branch1' }] }); + }); + it('should throw an error when passing an invalid resource', async () => { await expect( handleAutocompleteRequest({ 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..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,35 @@ 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) + throw new InputError( + 'Missing workspace and/or repository context parameter', + ); + + const results: { title: string }[] = []; + + for await (const page of client + .listBranchesByRepository(context.repository, context.workspace) + .iteratePages()) { + const names = [...page.values!].map(p => ({ title: p.name! })); + results.push(...names); + } + + return { results }; } default: throw new InputError(`Invalid resource: ${resource}`); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index 3443242e91..221a626169 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.1.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.13-next.1 + +### Patch Changes + +- e3b64be: Added examples for publish:bitbucketServer action and improve its test cases +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.12 + +### Patch Changes + +- 6a4ad4e: Instead of using hardcoded `targetBranch` now fetch the default branch from Bitbucket repository. + This prevents from errors when no `targetBranch` is provided and the default repository branch is different from `master`, for example: `main`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index b396faa5e5..5c08e23b6f 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-server", - "version": "0.1.12-next.1", + "version": "0.1.13-next.2", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -48,7 +48,7 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts index eae8385822..8e222a6876 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts @@ -29,12 +29,15 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerAction } from './bitbucketServer'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import yaml from 'yaml'; import { examples } from './bitbucketServer.examples'; -import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; +import { + getRepoSourceDirectory, + initRepoAndPush, +} from '@backstage/plugin-scaffolder-node'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; describe('publish:bitbucketServer', () => { @@ -68,7 +71,7 @@ describe('publish:bitbucketServer', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); @@ -266,7 +269,8 @@ describe('publish:bitbucketServer', () => { it(`should ${examples[3].description}`, async () => { expect.assertions(3); - server.use( + + const handlers = [ rest.post( 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', (req, res, ctx) => { @@ -300,7 +304,35 @@ describe('publish:bitbucketServer', () => { ); }, ), - ); + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); await action.handler({ ...mockContext, @@ -334,7 +366,8 @@ describe('publish:bitbucketServer', () => { it(`should ${examples[4].description}`, async () => { expect.assertions(3); - server.use( + + const handlers = [ rest.post( 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', (req, res, ctx) => { @@ -368,7 +401,35 @@ describe('publish:bitbucketServer', () => { ); }, ), - ); + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); await action.handler({ ...mockContext, @@ -399,4 +460,1050 @@ describe('publish:bitbucketServer', () => { gitAuthorInfo: { name: 'Test User', email: 'test.user@example.com' }, }); }); + it(`should ${examples[5].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe(`Bearer thing`); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'master', + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[5].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + // Ensure that the initRepoAndPush function was called with the correct remoteUrl and input properties + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + defaultBranch: 'master', + auth: { token: 'thing' }, + logger: mockContext.logger, + commitMessage: 'initial commit', + gitAuthorInfo: { + name: 'Custom Author', + email: 'custom.author@example.com', + }, + }); + }); + + it(`should ${examples[6].description}`, async () => { + expect.assertions(5); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'master', + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[6].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + defaultBranch: 'master', + auth: { token: 'thing' }, + logger: mockContext.logger, + commitMessage: 'Initial commit with LFS enabled', + gitAuthorInfo: { + email: input.gitAuthorName, + name: input.gitAuthorEmail, + }, + }); + }); + + it(`should ${examples[7].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer custom-token'); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'master', + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[7].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: getRepoSourceDirectory(mockContext.workspacePath, input.sourcePath), + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: 'custom-token' }, + defaultBranch: 'master', + logger: mockContext.logger, + commitMessage: 'initial commit', + gitAuthorInfo: { name: undefined, email: undefined }, + }); + }); + + it(`should ${examples[8].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'master', + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[8].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: 'thing' }, + defaultBranch: 'master', + logger: mockContext.logger, + commitMessage: 'initial commit', + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); + + it(`should ${examples[9].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual({ + public: true, + name: 'repo', + defaultBranch: 'master', + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[9].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: 'thing' }, + defaultBranch: 'master', + logger: mockContext.logger, + commitMessage: 'Public repository initial commit', + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); + + it(`should ${examples[10].description}`, async () => { + expect.assertions(5); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer custom-token'); + expect(req.body).toEqual({ + public: false, + name: 'repo', + description: 'A fully customized repository', + defaultBranch: 'development', + }); + + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer custom-token'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[10].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: getRepoSourceDirectory(mockContext.workspacePath, input.sourcePath), + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: input.token }, + defaultBranch: input.defaultBranch, + logger: mockContext.logger, + commitMessage: input.gitCommitMessage, + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); + + it(`should ${examples[11].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'main', + }); + + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer custom-token'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[11].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: input.sourcePath + ? getRepoSourceDirectory(mockContext.workspacePath, input.sourcePath) + : mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: input.token ?? 'thing' }, + defaultBranch: input.defaultBranch, + logger: mockContext.logger, + commitMessage: input.gitCommitMessage ?? 'initial commit', + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); + + it(`should ${examples[12].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual({ + public: true, + name: 'repo', + defaultBranch: 'master', + description: 'A public repository with a custom description', + }); + + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer custom-token'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[12].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: input.sourcePath + ? getRepoSourceDirectory(mockContext.workspacePath, input.sourcePath) + : mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: input.token ?? 'thing' }, + defaultBranch: input.defaultBranch ?? 'master', + logger: mockContext.logger, + commitMessage: input.gitCommitMessage ?? 'initial commit', + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); + + it(`should ${examples[13].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe( + 'Bearer custom-auth-token', + ); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'master', + }); + + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer custom-token'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[13].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: input.sourcePath + ? getRepoSourceDirectory(mockContext.workspacePath, input.sourcePath) + : mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: input.token ?? 'thing' }, + defaultBranch: input.defaultBranch ?? 'master', + logger: mockContext.logger, + commitMessage: input.gitCommitMessage ?? 'initial commit', + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); + + it(`should ${examples[14].description}`, async () => { + expect.assertions(3); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'master', + }); + + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer custom-token'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[14].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: input.sourcePath + ? getRepoSourceDirectory(mockContext.workspacePath, input.sourcePath) + : mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: input.token ?? 'thing' }, + defaultBranch: input.defaultBranch ?? 'master', + logger: mockContext.logger, + commitMessage: input.gitCommitMessage ?? 'initial commit', + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); + + it(`should ${examples[15].description}`, async () => { + expect.assertions(5); + + const handlers = [ + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/project/repos', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual({ + public: false, + name: 'repo', + defaultBranch: 'master', + }); + + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + { + href: 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/project/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + expect(req.body).toEqual(''); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }), + ); + }, + ), + ]; + + server.use(...handlers); + + let input; + try { + input = yaml.parse(examples[15].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: input.sourcePath + ? getRepoSourceDirectory(mockContext.workspacePath, input.sourcePath) + : mockContext.workspacePath, + remoteUrl: 'https://bitbucket.mycompany.com/scm/project/repo', + auth: { token: input.token ?? 'thing' }, + defaultBranch: input.defaultBranch ?? 'master', + logger: mockContext.logger, + commitMessage: input.gitCommitMessage ?? 'initial commit', + gitAuthorInfo: { name: input.gitAuthorName, email: input.gitAuthorEmail }, + }); + }); }); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.ts index b3a68eed57..e28f9ca48c 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.ts @@ -129,4 +129,207 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: + 'Initialize git repository with default settings and custom author information', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-custom-author', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + gitAuthorName: 'Custom Author', + gitAuthorEmail: 'custom.author@example.com', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with LFS enabled and a specific commit message', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-lfs-commit', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + enableLFS: true, + gitCommitMessage: 'Initial commit with LFS enabled', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with a custom source path and token', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-custom-source', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + sourcePath: 'custom/source/path', + token: 'custom-token', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with private visibility and custom author details', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-private-custom-author', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + repoVisibility: 'private', + gitAuthorName: 'Private Author', + gitAuthorEmail: 'private.author@example.com', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with public visibility and specific commit message', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-public-commit', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + repoVisibility: 'public', + gitCommitMessage: 'Public repository initial commit', + }, + }, + ], + }), + }, + { + description: 'Initialize git repository with all settings customized', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-all-custom', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + description: 'A fully customized repository', + repoVisibility: 'private', + defaultBranch: 'development', + sourcePath: 'src/backend', + enableLFS: true, + token: 'custom-token', + gitCommitMessage: 'Fully customized initial commit', + gitAuthorName: 'Custom Dev', + gitAuthorEmail: 'custom.dev@example.com', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with a specific default branch and no LFS', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-no-lfs', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + defaultBranch: 'main', + enableLFS: false, + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with a custom repository description and public visibility', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-custom-description', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + description: 'A public repository with a custom description', + repoVisibility: 'public', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with a custom token for authentication', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-custom-token', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + token: 'custom-auth-token', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with a different repository root path', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-different-root', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + sourcePath: 'different/root/path', + }, + }, + ], + }), + }, + { + description: + 'Initialize git repository with private visibility and LFS enabled', + example: yaml.stringify({ + steps: [ + { + action: 'publish:bitbucketServer', + id: 'publish-bitbucket-server-private-lfs', + name: 'Publish To Bitbucket Server', + input: { + repoUrl: 'hosted.bitbucket.com?project=project&repo=repo', + repoVisibility: 'private', + enableLFS: true, + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts index 1d42e7368c..250b3f9b54 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerAction } from './bitbucketServer'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -66,7 +66,7 @@ describe('publish:bitbucketServer', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts index 1d3556fc88..b83ba2be55 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerPullRequestAction } from './bitbucketServerPullRequest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import yaml from 'yaml'; @@ -191,7 +191,7 @@ describe('publish:bitbucketServer:pull-request', () => { }; const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts index 61adf0e3c8..37df535fec 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerPullRequestAction } from './bitbucketServerPullRequest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; @@ -221,7 +221,7 @@ describe('publish:bitbucketServer:pull-request', () => { ]; const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 35f5382652..062d54226d 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.2.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index bca6e94878..a9f499ec74 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", - "version": "0.2.12-next.1", + "version": "0.2.13-next.2", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -50,7 +50,7 @@ "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts index 6633246d70..d452f2e11f 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketAction } from './bitbucket'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -67,7 +67,7 @@ describe('publish:bitbucket', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts index a63d657904..654b0fffcb 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts @@ -28,7 +28,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketAction } from './bitbucket'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -63,7 +63,7 @@ describe('publish:bitbucket', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts b/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts index a17c88c3a4..a9daa771f0 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts @@ -19,25 +19,29 @@ import * as bitbucketServer from '@backstage/plugin-scaffolder-backend-module-bi export { createPublishBitbucketAction } from './actions/bitbucket'; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead */ export const createPublishBitbucketCloudAction = bitbucketCloud.createPublishBitbucketCloudAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead */ export const createBitbucketPipelinesRunAction = bitbucketCloud.createBitbucketPipelinesRunAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerAction = bitbucketServer.createPublishBitbucketServerAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerPullRequestAction = bitbucketServer.createPublishBitbucketServerPullRequestAction; diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index b3c7bfbe36..2621b1d8f3 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.2.24-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.2.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.2.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.2.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.23-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index f607696136..b4b10f7d4c 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", - "version": "0.2.23-next.1", + "version": "0.2.24-next.2", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -53,7 +53,7 @@ "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", "git-url-parse": "^14.0.0", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "node-html-markdown": "^1.3.0", "yaml": "^2.0.0" }, diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts index da82849c1e..36ae750723 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts @@ -20,7 +20,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -32,7 +32,7 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- describe('confluence:transform:markdown examples', () => { const baseUrl = `https://confluence.example.com`; const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); const config = new ConfigReader({ confluence: { diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts index b19259b3df..4c3c6b891f 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts @@ -21,7 +21,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import type { ActionContext } from '@backstage/plugin-scaffolder-node'; import { rest } from 'msw'; @@ -31,7 +31,7 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- describe('confluence:transform:markdown', () => { const baseUrl = `https://nodomain.confluence.com`; const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); const config = new ConfigReader({ confluence: { diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 5854e9ff47..160953da23 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.47-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.2.47-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.2.47-next.0 + +### Patch Changes + +- dae85df: Add examples for `fetch:cookiecutter` scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.2.46 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.46-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 43a7e348a4..7749830304 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", - "version": "0.2.46-next.1", + "version": "0.2.47-next.2", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", "backstage": { "role": "backend-plugin-module", @@ -53,6 +53,7 @@ "command-exists": "^1.2.9", "fs-extra": "^11.2.0", "winston": "^3.2.1", + "yaml": "^2.0.0", "yn": "^4.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.test.ts b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.test.ts new file mode 100644 index 0000000000..ae46ef1bd6 --- /dev/null +++ b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.test.ts @@ -0,0 +1,274 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { UrlReader, ContainerRunner } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { ScmIntegrations } from '@backstage/integration'; +import { createMockDirectory } from '@backstage/backend-test-utils'; +import { createFetchCookiecutterAction } from './cookiecutter'; +import { join } from 'path'; +import type { ActionContext } from '@backstage/plugin-scaffolder-node'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { examples } from './cookiecutter.examples'; +import yaml from 'yaml'; + +const executeShellCommand = jest.fn(); +const commandExists = jest.fn(); +const fetchContents = jest.fn(); + +jest.mock('@backstage/plugin-scaffolder-node', () => ({ + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + fetchContents: (...args: any[]) => fetchContents(...args), + executeShellCommand: (...args: any[]) => executeShellCommand(...args), +})); + +jest.mock( + 'command-exists', + () => + (...args: any[]) => + commandExists(...args), +); + +describe('fetch:cookiecutter', () => { + const mockDir = createMockDirectory({ mockOsTmpDir: true }); + const integrations = ScmIntegrations.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { host: 'dev.azure.com', token: 'tokenlols' }, + { host: 'myazurehostnotoken.com' }, + ], + }, + }), + ); + + const mockTmpDir = mockDir.path; + + let mockContext: ActionContext<{ + url: string; + targetPath?: string; + values: JsonObject; + copyWithoutRender?: string[]; + extensions?: string[]; + imageName?: string; + }>; + + const containerRunner: jest.Mocked = { + runContainer: jest.fn(), + }; + + const mockReader: UrlReader = { + readUrl: jest.fn(), + readTree: jest.fn(), + search: jest.fn(), + }; + + const action = createFetchCookiecutterAction({ + integrations, + containerRunner, + reader: mockReader, + }); + + beforeEach(() => { + jest.resetAllMocks(); + + mockContext = createMockActionContext({ + input: { + url: 'https://google.com/cookie/cutter', + targetPath: 'something', + values: { + help: 'me', + }, + }, + templateInfo: { + entityRef: 'template:default/cookiecutter', + baseUrl: 'somebase', + }, + workspacePath: mockTmpDir, + }); + mockDir.setContent({ template: {} }); + + commandExists.mockResolvedValue(null); + + // Mock when run container is called it creates some new files in the mock filesystem + containerRunner.runContainer.mockImplementation(async () => { + mockDir.setContent({ + 'intermediate/testfile.json': '{}', + }); + }); + + // Mock when executeShellCommand is called it creates some new files in the mock filesystem + executeShellCommand.mockImplementation(async () => { + mockDir.setContent({ + 'intermediate/testfile.json': '{}', + }); + }); + }); + + it(`should ${examples[0].description}`, async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[1].description}`, async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: input, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[2].description}`, async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[3].description}`, async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[4].description}`, async () => { + const input = yaml.parse(examples[4].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); +}); diff --git a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.ts b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.ts new file mode 100644 index 0000000000..6ebada50f0 --- /dev/null +++ b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.ts @@ -0,0 +1,119 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Fetch and template using cookiecutter with minimal options.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with custom target path.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + targetPath: 'custom-path', + values: { + help: 'me', + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with copyWithoutRender.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + copyWithoutRender: ['.github/*', '*.md'], + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with custom extensions.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + extensions: ['jinja2_time.TimeExtension'], + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with a custom Docker image.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + imageName: 'custom/cookiecutter-image', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts index d170acb5d0..efbe0a07cf 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts +++ b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts @@ -28,6 +28,7 @@ import { fetchContents, executeShellCommand, } from '@backstage/plugin-scaffolder-node'; +import { examples } from './cookiecutter.examples'; export class CookiecutterRunner { private readonly containerRunner?: ContainerRunner; @@ -156,6 +157,7 @@ export function createFetchCookiecutterAction(options: { id: 'fetch:cookiecutter', description: 'Downloads a template from the given URL into the workspace, and runs cookiecutter on it.', + examples, schema: { input: { type: 'object', diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md index e32c2ef08f..c759549d90 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.0 + +### Minor Changes + +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.0-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index c441acb21a..33459ba5b6 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gcp", - "version": "0.1.0-next.3", + "version": "0.1.1-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 dd26e1d5a8..811e9a80cc 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.1.15-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.14-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 31a30c3f7e..0e50124013 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", - "version": "0.1.14-next.1", + "version": "0.1.15-next.2", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -47,7 +47,7 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts index 1f069d3835..c102353209 100644 --- a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts @@ -30,7 +30,7 @@ import path from 'path'; import { createPublishGerritAction } from './gerrit'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -61,7 +61,7 @@ describe('publish:gerrit', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index f3ceb7ce8c..0a05340f77 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.1.13-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.13-next.1 + +### Patch Changes + +- 24de005: Added test cases for publish:gitea examples +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 3cacbc66db..cb888b65ad 100644 --- a/plugins/scaffolder-backend-module-gitea/package.json +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitea", - "version": "0.1.12-next.1", + "version": "0.1.13-next.2", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -47,7 +47,7 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.test.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.test.ts new file mode 100644 index 0000000000..5575921c34 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.test.ts @@ -0,0 +1,806 @@ +/* + * 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 { ScmIntegrations } from '@backstage/integration'; +import { ConfigReader } from '@backstage/config'; +import { createPublishGiteaAction } from './gitea'; +import { + getRepoSourceDirectory, + initRepoAndPush, +} from '@backstage/plugin-scaffolder-node'; +import { rest } from 'msw'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { setupServer } from 'msw/node'; +import { examples } from './gitea.examples'; +import yaml from 'yaml'; + +jest.mock('@backstage/plugin-scaffolder-node', () => { + return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + initRepoAndPush: jest.fn().mockResolvedValue({ + commitHash: '431f19cc36b551763d157f1b5e4a4b446165dbn2', + }), + }; +}); + +describe('publish:gitea', () => { + const config = new ConfigReader({ + integrations: { + gitea: [ + { + host: 'gitea.com', + username: 'sample_user', + password: 'password_token', + }, + ], + }, + }); + + const description = 'gitea description'; + const integrations = ScmIntegrations.fromConfig(config); + const action = createPublishGiteaAction({ integrations, config }); + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + description, + }, + }); + + const server = setupServer(); + registerMswTestHooks(server); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it(`should ${examples[0].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + }); + + it(`should ${examples[1].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description: 'Initialize a gitea repository', + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + }); + + it(`should ${examples[2].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: true, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + }); + + it(`should ${examples[3].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/staging', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[3].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'staging', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + }); + + it(`should ${examples[4].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[4].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining( + 'Initial Commit Message\n\nChange-Id:', + ), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + }); + + it(`should ${examples[5].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[5].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: 'John Doe', + }, + }); + }); + + it(`should ${examples[6].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[6].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: 'johndoe@email.com', + name: undefined, + }, + }); + }); + + it(`should ${examples[7].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[7].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: getRepoSourceDirectory(mockContext.workspacePath, 'repository/'), + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + }); + + it(`should ${examples[8].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/staging', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description: 'Initialize a gitea repository', + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[8].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: getRepoSourceDirectory(mockContext.workspacePath, 'repository/'), + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'staging', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining( + 'Initial Commit Message\n\nChange-Id:', + ), + gitAuthorInfo: { + email: 'johndoe@email.com', + name: 'John Doe', + }, + }); + }); + + it(`should ${examples[0].description}`, async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic c2FtcGxlX3VzZXI6cGFzc3dvcmRfdG9rZW4=', + ); + expect(req.body).toEqual({ + name: 'repo', + private: false, + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'sample_user', password: 'password_token' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts index dd4d038ead..5cf640de87 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts @@ -78,7 +78,7 @@ export const examples: TemplateExample[] = [ name: 'Publish to Gitea', input: { repoUrl: 'gitea.com?repo=repo&owner=owner', - defaultBranch: 'main', + defaultBranch: 'staging', }, }, ], diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts index 8a72265df0..7812ded60a 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts @@ -18,7 +18,7 @@ import { ConfigReader } from '@backstage/config'; import { createPublishGiteaAction } from './gitea'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; import { rest } from 'msw'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { setupServer } from 'msw/node'; @@ -62,7 +62,7 @@ describe('publish:gitea', () => { }); const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index 2d3c6ff0f2..e9d841aa0c 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,68 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.4.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.4.1-next.1 + +### Patch Changes + +- d21d307: Added examples for github:environment:create action and improve its test cases +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.4.0 + +### Minor Changes + +- 70c4b36: Adds support for custom tag policies when creating GitHub environments. + +### Patch Changes + +- ccfc9d1: Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`. + + Adding environment secrets now works as expected. + +- 141f366: Added action to enable GitHub Pages on a repo +- 4410fed: Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action +- dfaa28d: Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action + + Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.4.0-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 500ec86f9f..c373839d13 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", - "version": "0.4.0-next.1", + "version": "0.4.1-next.2", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/src/actions/gitHubEnvironment.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/gitHubEnvironment.examples.ts index 606424bef0..7c5f7efa3d 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/gitHubEnvironment.examples.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/gitHubEnvironment.examples.ts @@ -96,4 +96,210 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Create a GitHub Environment with Custom Tag Policies', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + customTagPolicyNames: ['release/*/*', 'v*.*.*'], + }, + }, + ], + }), + }, + { + description: + 'Create a GitHub Environment with Both Branch and Tag Policies', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + deploymentBranchPolicy: { + protected_branches: false, + custom_branch_policies: true, + }, + customBranchPolicyNames: ['feature/*', 'hotfix/*'], + customTagPolicyNames: ['release/*', 'v*'], + }, + }, + ], + }), + }, + { + description: 'Create a GitHub Environment with Full Configuration', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + deploymentBranchPolicy: { + protected_branches: false, + custom_branch_policies: true, + }, + customBranchPolicyNames: ['dev/*', 'test/*'], + customTagPolicyNames: ['v1.*', 'v2.*'], + environmentVariables: { + API_KEY: '123456789', + NODE_ENV: 'production', + }, + secrets: { + DATABASE_URL: 'supersecretdatabaseurl', + API_SECRET: 'supersecretapisecret', + }, + token: 'ghp_abcdef1234567890', + }, + }, + ], + }), + }, + { + description: 'Create a GitHub Environment with Only Token Authentication', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + token: 'ghp_abcdef1234567890', + }, + }, + ], + }), + }, + { + description: 'Create a GitHub Environment with No Deployment Policies', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + deploymentBranchPolicy: null, + }, + }, + ], + }), + }, + { + description: + 'Create a GitHub Environment with Custom Branch and Tag Policies', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + deploymentBranchPolicy: { + protected_branches: false, + custom_branch_policies: true, + }, + customBranchPolicyNames: ['release/*', 'hotfix/*'], + customTagPolicyNames: ['v*', 'release-*'], + }, + }, + ], + }), + }, + { + description: 'Create a GitHub Environment with Environment Variables Only', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + environmentVariables: { + VAR1: 'value1', + VAR2: 'value2', + }, + }, + }, + ], + }), + }, + { + description: 'Create a GitHub Environment with Deployment Secrets Only', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + secrets: { + SECRET1: 'secretvalue1', + SECRET2: 'secretvalue2', + }, + }, + }, + ], + }), + }, + { + description: + 'Create a GitHub Environment with Deployment Branch Policy and Token', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + deploymentBranchPolicy: { + protected_branches: true, + custom_branch_policies: false, + }, + token: 'ghp_abcdef1234567890', + }, + }, + ], + }), + }, + { + description: + 'Create a GitHub Environment with Environment Variables, Secrets, and Token', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + environmentVariables: { + VAR1: 'value1', + VAR2: 'value2', + }, + secrets: { + SECRET1: 'secretvalue1', + SECRET2: 'secretvalue2', + }, + token: 'ghp_abcdef1234567890', + }, + }, + ], + }), + }, ]; 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 e41e642ca0..c8b133859b 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 @@ -264,4 +264,522 @@ describe('github:environment:create examples', () => { encrypted_value: expect.any(String), }); }); + + it(`should ${examples[4].description}`, async () => { + const input = yaml.parse(examples[4].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'release/*/*', + owner: 'owner', + repo: 'repository', + type: 'tag', + }); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'v*.*.*', + owner: 'owner', + repo: 'repository', + type: 'tag', + }); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it(`should ${examples[5].description}`, async () => { + const input = yaml.parse(examples[5].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: { + custom_branch_policies: true, + protected_branches: false, + }, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledTimes(4); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'release/*', + owner: 'owner', + repo: 'repository', + type: 'tag', + }); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'feature/*', + owner: 'owner', + repo: 'repository', + type: 'branch', + }); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it(`should ${examples[6].description}`, async () => { + const input = yaml.parse(examples[6].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: { + custom_branch_policies: true, + protected_branches: false, + }, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledTimes(4); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'dev/*', + owner: 'owner', + repo: 'repository', + type: 'branch', + }); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'test/*', + owner: 'owner', + repo: 'repository', + type: 'branch', + }); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledTimes(2); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'API_KEY', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + value: '123456789', + }); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'NODE_ENV', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + value: 'production', + }); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + encrypted_value: expect.any(String), + environment_name: 'envname', + key_id: 'keyid', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + secret_name: 'API_SECRET', + }); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + encrypted_value: expect.any(String), + environment_name: 'envname', + key_id: 'keyid', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + secret_name: 'DATABASE_URL', + }); + }); + + it(`should ${examples[7].description}`, async () => { + const input = yaml.parse(examples[7].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it(`should ${examples[8].description}`, async () => { + const input = yaml.parse(examples[8].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it(`should ${examples[9].description}`, async () => { + const input = yaml.parse(examples[9].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: { + custom_branch_policies: true, + protected_branches: false, + }, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledTimes(4); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'release/*', + owner: 'owner', + repo: 'repository', + type: 'branch', + }); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'hotfix/*', + owner: 'owner', + repo: 'repository', + type: 'branch', + }); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'v*', + owner: 'owner', + repo: 'repository', + type: 'tag', + }); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it(`should ${examples[10].description}`, async () => { + const input = yaml.parse(examples[10].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'VAR1', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + value: 'value1', + }); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'VAR2', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + value: 'value2', + }); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it(`should ${examples[11].description}`, async () => { + const input = yaml.parse(examples[11].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + encrypted_value: expect.any(String), + environment_name: 'envname', + key_id: 'keyid', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + secret_name: 'SECRET1', + }); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + encrypted_value: expect.any(String), + environment_name: 'envname', + key_id: 'keyid', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + secret_name: 'SECRET2', + }); + }); + + it(`should ${examples[12].description}`, async () => { + const input = yaml.parse(examples[12].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: { + custom_branch_policies: false, + protected_branches: true, + }, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it(`should ${examples[13].description}`, async () => { + const input = yaml.parse(examples[13].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'VAR1', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + value: 'value1', + }); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + environment_name: 'envname', + name: 'VAR2', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + value: 'value2', + }); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + encrypted_value: expect.any(String), + environment_name: 'envname', + key_id: 'keyid', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + secret_name: 'SECRET1', + }); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + encrypted_value: expect.any(String), + environment_name: 'envname', + key_id: 'keyid', + owner: 'owner', + repo: 'repository', + repository_id: 'repoid', + secret_name: 'SECRET2', + }); + }); }); diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 0c8f0529a6..f62e5b4db8 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,66 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.4.5-next.0 + +### Patch Changes + +- fad1b90: Allow the `createGitlabProjectVariableAction` to use oauth tokens +- aab708e: Added test cases for gitlab:issue:edit examples +- ef742dc: Added test cases for gitlab:projectAccessToken:create example +- 1ba4c2f: Added test cases for gitlab:pipeline:trigger examples +- a6603e4: Add custom action for merge request: **auto** + + The **Auto** action selects the committed action between _create_ and _update_. + + The **Auto** action fetches files using the **/projects/repository/tree endpoint**. + After fetching, it checks if the file exists locally and in the repository. If it does, it chooses **update**; otherwise, it chooses **create**. + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.4.4 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- 2fb0eb8: Added support for passing `variables` to `gitlab:pipeline:trigger` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/api-report.md b/plugins/scaffolder-backend-module-gitlab/api-report.md index b1f240029e..ab89669ede 100644 --- a/plugins/scaffolder-backend-module-gitlab/api-report.md +++ b/plugins/scaffolder-backend-module-gitlab/api-report.md @@ -193,7 +193,7 @@ export const createPublishGitlabMergeRequestAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'update' | 'delete' | 'create' | undefined; + commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 499cfd6872..dde6e48a6e 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.4.4-next.1", + "version": "0.4.5-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts new file mode 100644 index 0000000000..7e50eac66c --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts @@ -0,0 +1,817 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { ConfigReader } from '@backstage/core-app-api'; +import { ScmIntegrations } from '@backstage/integration'; +import { editGitlabIssueAction } from './gitlabIssueEdit'; +import { examples } from './gitlabIssueEdit.examples'; +import yaml from 'yaml'; + +const mockGitlabClient = { + Issues: { + edit: jest.fn(), + }, +}; +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:issue:edit', () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.useFakeTimers({ + now: new Date(1999, 6, 14, 12, 0, 0), + }); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'myIntegrationsToken', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, + }); + const integrations = ScmIntegrations.fromConfig(config); + + const action = editGitlabIssueAction({ integrations }); + + it(`Should ${examples[0].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[1].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: '2024-05-10T18:00:00.000Z', + dueDate: '2024-09-28', + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[2].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + epicId: undefined, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18, 15], + confidential: false, + discussionLocked: true, + epicId: undefined, + labels: 'phase1:label1,phase2:label2', + updatedAt: '2024-05-10T18:00:00.000Z', + dueDate: '2024-09-28', + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[2].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + epicId: undefined, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18, 15], + confidential: false, + discussionLocked: true, + epicId: undefined, + labels: 'phase1:label1,phase2:label2', + updatedAt: '2024-05-10T18:00:00.000Z', + dueDate: '2024-09-28', + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[3].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[3].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: 'Computer banks to rule the world', + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: undefined, + weight: undefined, + stateEvent: 'close', + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[4].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[4].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: 'Computer banks to rule the world', + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: undefined, + weight: undefined, + stateEvent: 'reopen', + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[5].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[5].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18, 20], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[6].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[6].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[7].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[7].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: input.confidential, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[8].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[8].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: input.discussionLocked, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[9].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[9].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: input.removeLabels, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + it(`Should ${examples[10].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[10].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: input.removeLabels, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + it(`Should ${examples[11].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[11].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: input.issueType, + addLabels: undefined, + removeLabels: input.removeLabels, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts index 861c0736f0..8686a66250 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts @@ -50,7 +50,7 @@ export const examples: TemplateExample[] = [ title: 'Test Issue', assignees: [18], description: 'This is the edited description of the issue', - updatedAt: '2024-05-10 18:00:00.000', + updatedAt: '2024-05-10T18:00:00.000Z', dueDate: '2024-09-28', }, }, @@ -72,7 +72,7 @@ export const examples: TemplateExample[] = [ assignees: [18, 15], description: 'This is the description of the issue', confidential: false, - updatedAt: '2024-05-10 18:00:00.000', + updatedAt: '2024-05-10T18:00:00.000Z', dueDate: '2024-09-28', discussionLocked: true, epicId: 1, @@ -82,4 +82,177 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Edit a gitlab issue to change its state to close', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + stateEvent: 'close', + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to change its state to reopened', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + stateEvent: 'reopen', + }, + }, + ], + }), + }, + { + description: + 'Edit a gitlab issue to assign it to multiple users and set milestone', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Test issue with milestone', + assignees: [18, 20], + description: 'This issue has milestone set', + milestoneId: 5, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to add weight and update labels', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with weight and labels', + description: 'This issue has weight and new labels', + weight: 3, + labels: 'bug,urgent', + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to make it confidential', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Confidential Issue', + description: 'This issue is confidential', + confidential: true, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to lock the discussion', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Locked Discussion Issue', + description: 'This discussion on this issue is locked', + discussionLocked: true, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to remove labels and update milestone', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with labels removed and milestone updated', + description: 'This issue has labels removed and milestone updated', + removeLabels: 'phase1:label1', + milestoneId: 6, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to remove some labels and new ones', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with labels updated', + description: 'This issue has labels removed and new ones added', + removeLabels: 'bug,urgent', + labels: 'enhancement:documentation', + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to change issue type and add labels', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with type and labels', + description: 'This issue has been changes and new labels added', + labels: 'task,high-priority', + issueType: 'task', + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts index befc2c01c9..3eda50a924 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts @@ -61,6 +61,28 @@ const mockGitlabClient = { ]; }), }, + Repositories: { + tree: jest.fn( + async ( + repoID: string | number, + options: { ref: string; recursive: boolean; path: string | undefined }, + ) => { + if (repoID !== 'owner/repo') throw new Error('repo does not exist'); + if (options.recursive === false) throw new Error('malformed options'); + else { + return [ + { + id: 'a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba', + name: 'auto.txt', + type: 'blob', + path: 'source/auto.txt', + mode: '040000', + }, + ]; + } + }, + ), + }, }; jest.mock('@gitbeaker/node', () => ({ @@ -407,7 +429,7 @@ describe('createGitLabMergeRequest', () => { }); describe('createGitLabMergeRequestWithoutCommitAction', () => { - it('default commitAction is create', async () => { + it('default commitAction is auto', async () => { const input = { repoUrl: 'gitlab.com?repo=repo&owner=owner', title: 'Create my new MR', @@ -417,7 +439,7 @@ describe('createGitLabMergeRequest', () => { }; mockDir.setContent({ [workspacePath]: { - source: { 'foo.txt': 'Hello there!' }, + source: { 'foo.txt': 'Hello there!', 'auto.txt': 'File exist' }, irrelevant: { 'bar.txt': 'Nothing to see here' }, }, }); @@ -429,6 +451,13 @@ describe('createGitLabMergeRequest', () => { 'new-mr', 'Create my new MR', [ + { + action: 'update', + filePath: 'source/auto.txt', + content: 'RmlsZSBleGlzdA==', + encoding: 'base64', + execute_filemode: false, + }, { action: 'create', filePath: 'source/foo.txt', @@ -512,6 +541,88 @@ describe('createGitLabMergeRequest', () => { ); }); + it('commitAction is auto when auto is passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + title: 'Create my new MR', + branchName: 'new-mr', + description: 'MR description', + commitAction: 'auto', + }; + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!', 'auto.txt': 'File exist' }, + }, + }); + + const ctx = createMockActionContext({ input, workspacePath }); + await instance.handler(ctx); + + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'new-mr', + 'Create my new MR', + [ + { + action: 'update', + filePath: 'source/auto.txt', + content: 'RmlsZSBleGlzdA==', + encoding: 'base64', + execute_filemode: false, + }, + { + action: 'create', + filePath: 'source/foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + }); + + it('commitAction is auto when auto is passed in options with targetPath', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + title: 'Create my new MR', + branchName: 'new-mr', + description: 'MR description', + commitAction: 'auto', + targetPath: 'source', + }; + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!', 'auto.txt': 'File exist' }, + irrevelant: {}, + }, + }); + + const ctx = createMockActionContext({ input, workspacePath }); + await instance.handler(ctx); + + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'new-mr', + 'Create my new MR', + [ + { + action: 'update', + filePath: 'source/auto.txt', + content: 'RmlsZSBleGlzdA==', + encoding: 'base64', + execute_filemode: false, + }, + { + action: 'create', + filePath: 'source/foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + }); + it('commitAction is delete when delete is passed in options', async () => { const input = { repoUrl: 'gitlab.com?repo=repo&owner=owner', diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index a549585426..733365c6df 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -17,6 +17,7 @@ import { createTemplateAction, parseRepoUrl, + SerializedFile, serializeDirectoryContents, } from '@backstage/plugin-scaffolder-node'; import { Types } from '@gitbeaker/core'; @@ -27,6 +28,21 @@ import { resolveSafeChildPath } from '@backstage/backend-plugin-api'; import { createGitlabApi } from './helpers'; import { examples } from './gitlabMergeRequest.examples'; +function getFileAction( + fileInfo: { file: SerializedFile; targetPath: string | undefined }, + remoteFiles: Types.RepositoryTreeSchema[], + defaultCommitAction: 'create' | 'delete' | 'update' | 'auto' | undefined, +): 'create' | 'delete' | 'update' { + if (!defaultCommitAction || defaultCommitAction === 'auto') { + const filePath = path.join(fileInfo.targetPath ?? '', fileInfo.file.path); + return remoteFiles && + remoteFiles.some(remoteFile => remoteFile.path === filePath) + ? 'update' + : 'create'; + } + return defaultCommitAction; +} + /** * Create a new action that creates a gitlab merge request. * @@ -46,7 +62,7 @@ export const createPublishGitlabMergeRequestAction = (options: { sourcePath?: string; targetPath?: string; token?: string; - commitAction?: 'create' | 'delete' | 'update'; + commitAction?: 'create' | 'delete' | 'update' | 'auto'; /** @deprecated projectID passed as query parameters in the repoUrl */ projectid?: string; removeSourceBranch?: boolean; @@ -109,9 +125,9 @@ export const createPublishGitlabMergeRequestAction = (options: { commitAction: { title: 'Commit action', type: 'string', - enum: ['create', 'update', 'delete'], + enum: ['create', 'update', 'delete', 'auto'], description: - 'The action to be used for git commit. Defaults to create.', + 'The action to be used for git commit. Defaults to auto. "auto" is custom action provide by backstage, (automatic assign create or update action) /!\\ Use more api calls /!\\ *', }, removeSourceBranch: { title: 'Delete source branch', @@ -199,16 +215,6 @@ export const createPublishGitlabMergeRequestAction = (options: { gitignore: true, }); - const actions: Types.CommitAction[] = fileContents.map(file => ({ - action: ctx.input.commitAction ?? 'create', - filePath: targetPath - ? path.posix.join(targetPath, file.path) - : file.path, - encoding: 'base64', - content: file.content.toString('base64'), - execute_filemode: file.executable, - })); - let targetBranch = targetBranchName; if (!targetBranch) { const projects = await api.Projects.show(repoID); @@ -217,6 +223,35 @@ export const createPublishGitlabMergeRequestAction = (options: { targetBranch = defaultBranch!; } + let remoteFiles: Types.RepositoryTreeSchema[] = []; + if (!ctx.input.commitAction || ctx.input.commitAction === 'auto') { + try { + remoteFiles = await api.Repositories.tree(repoID, { + ref: targetBranch, + recursive: true, + path: targetPath ?? undefined, + }); + } catch (e) { + ctx.logger.warn( + `Could not retrieve the list of files for ${repoID} (branch: ${targetBranch}) : ${e}`, + ); + } + } + + const actions: Types.CommitAction[] = fileContents.map(file => ({ + action: getFileAction( + { file, targetPath }, + remoteFiles, + ctx.input.commitAction, + ), + filePath: targetPath + ? path.posix.join(targetPath, file.path) + : file.path, + encoding: 'base64', + content: file.content.toString('base64'), + execute_filemode: file.executable, + })); + try { await api.Branches.create(repoID, branchName, String(targetBranch)); } catch (e) { diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts new file mode 100644 index 0000000000..53cbfb0b87 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts @@ -0,0 +1,320 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigReader } from '@backstage/core-app-api'; +import { ScmIntegrations } from '@backstage/integration'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { createTriggerGitlabPipelineAction } from './gitlabPipelineTrigger'; +import { examples } from './gitlabPipelineTrigger.examples'; +import yaml from 'yaml'; + +const mockGitlabClient = { + PipelineTriggerTokens: { + create: jest.fn(), + trigger: jest.fn(), + remove: jest.fn(), + }, +}; +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:pipeline:trigger', () => { + beforeEach(() => { + jest.resetModules(); + jest.clearAllMocks(); + jest.useFakeTimers({ + now: new Date(1988, 5, 3, 12, 0, 0), + }); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'glpat-abcdef', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, + }); + const integrations = ScmIntegrations.fromConfig(config); + + const action = createTriggerGitlabPipelineAction({ integrations }); + + it(`should ${examples[0].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); + + it(`should ${examples[1].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); + it(`should ${examples[2].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); + it(`should ${examples[3].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[3].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts index d0840030df..f213fcd83f 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts @@ -39,4 +39,67 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Trigger a GitLab Project Pipeline with No Variables', + example: yaml.stringify({ + steps: [ + { + id: 'triggerPipeline', + name: 'Trigger Project Pipeline', + action: 'gitlab:pipeline:trigger', + input: { + ...commonGitlabConfigExample, + projectId: 12, + tokenDescription: + 'This is the text that will appear in the pipeline token', + token: 'glpt-xxxxxxxxxxxx', + branch: 'main', + variables: {}, + }, + }, + ], + }), + }, + { + description: 'Trigger a GitLab Project Pipeline with Single Variables', + example: yaml.stringify({ + steps: [ + { + id: 'triggerPipeline', + name: 'Trigger Project Pipeline', + action: 'gitlab:pipeline:trigger', + input: { + ...commonGitlabConfigExample, + projectId: 12, + tokenDescription: + 'This is the text that will appear in the pipeline token', + token: 'glpt-xxxxxxxxxxxx', + branch: 'main', + variables: { var_one: 'one' }, + }, + }, + ], + }), + }, + { + description: 'Trigger a GitLab Project Pipeline with Multiple Variables', + example: yaml.stringify({ + steps: [ + { + id: 'triggerPipeline', + name: 'Trigger Project Pipeline', + action: 'gitlab:pipeline:trigger', + input: { + ...commonGitlabConfigExample, + projectId: 12, + tokenDescription: + 'This is the text that will appear in the pipeline token', + token: 'glpt-xxxxxxxxxxxx', + branch: 'main', + variables: { var_one: 'one', var_two: 'two', var_three: 'three' }, + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts index 811926cc82..bdf14ce1c8 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts @@ -51,6 +51,10 @@ describe('gitlab:projectAccessToken:create examples', () => { host: 'hosted.gitlab.com', apiBaseUrl: 'https://api.hosted.gitlab.com', }, + { + host: 'gitlab.example.com', + apiBaseUrl: 'https://api.gitlab.example.com', + }, ], }, }); @@ -192,4 +196,256 @@ describe('gitlab:projectAccessToken:create examples', () => { expect(mockContext.output).toHaveBeenCalledWith('access_token', 'TOKEN'); }); + + it(`should ${examples[5].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[5].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '456', + 'tokenname', + ['read_repository'], + { + accessLevel: 30, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[6].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[6].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '456', + 'full-access-token', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '2024-12-31', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[7].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[7].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[8].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[8].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository', 'read_api'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[9].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[9].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 10, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[10].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[10].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[11].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[11].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 50, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[12].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[12].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'no-expiry-token', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[13].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[13].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); }); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts index 8d4f335a46..89f8ae6269 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts @@ -102,4 +102,162 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Create a GitLab project access token with an access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '456', + accessLevel: 30, + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with multiple options', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '456', + accessLevel: 40, + name: 'full-access-token', + expiresAt: '2024-12-31', + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token with a token for authorization', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + token: 'personal-access-token', + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with read-only scopes', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + scopes: ['read_repository', 'read_api'], + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with guest access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + accessLevel: 10, + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token with maintainer access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + accessLevel: 40, + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with owner access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + accessLevel: 50, + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token with a specified name and no expiration date', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + name: 'no-expiry-token', + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token for a specific gitlab instance', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.example.com?repo=repo&owner=owner', + projectId: '101112', + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts new file mode 100644 index 0000000000..34ce8878f2 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts @@ -0,0 +1,221 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { createGitlabProjectAccessTokenAction } from './gitlabProjectAccessTokenCreate'; // Adjust the import based on your project structure + +import { DateTime } from 'luxon'; + +jest.mock('node-fetch'); + +const mockGitlabClient = { + ProjectAccessTokens: { + create: jest.fn(), + }, +}; + +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:projectAccessToken:create examples', () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'gitlab-token', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createGitlabProjectAccessTokenAction({ integrations }); + + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + }, + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should create a GitLab project access token with minimal options.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '987', + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '987', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with custom scopes.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '987', + scopes: ['read_registry', 'write_repository'], + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '987', + 'tokenname', + ['read_registry', 'write_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with a specified name.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '2110', + name: 'token', + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '2110', + 'token', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with a numeric project ID.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 23, + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + 23, + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with a specified expired Date.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '123', + expiresAt: '1999-07-14', + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '123', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '1999-07-14', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); +}); 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, }); }, }); diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index 6371124957..85da251d02 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-notifications-node@0.2.4-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-notifications-common@0.0.5 + +## 0.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.0.6-next.0 + +### Patch Changes + +- 6fc03c7: Add examples for notification:send scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + ## 0.0.5-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index 7c983c36ce..204bf597e9 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-notifications", - "version": "0.0.5-next.1", + "version": "0.0.6-next.2", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", @@ -38,7 +38,8 @@ "@backstage/plugin-notifications-common": "workspace:^", "@backstage/plugin-notifications-node": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "octokit": "^3.0.0" + "octokit": "^3.0.0", + "yaml": "^2.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.test.ts b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.test.ts new file mode 100644 index 0000000000..84473335e0 --- /dev/null +++ b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.test.ts @@ -0,0 +1,272 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createSendNotificationAction } from './sendNotification'; +import { NotificationService } from '@backstage/plugin-notifications-node'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { examples } from './sendNotification.examples'; +import yaml from 'yaml'; + +describe('notification:send', () => { + const notificationService: jest.Mocked = { + send: jest.fn(), + }; + + let action: TemplateAction; + + beforeEach(() => { + jest.resetAllMocks(); + action = createSendNotificationAction({ + notifications: notificationService, + }); + }); + + const mockContext = createMockActionContext({ + input: { + recipients: 'broadcast', + title: 'Test notification', + }, + }); + + it(`should ${examples[0].description}`, async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + title: 'Test notification', + }, + }); + }); + + it(`should ${examples[1].description}`, async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + entityRef: ['entity:component:1'], + type: 'entity', + }, + payload: { + description: 'A security update has been applied. Please review.', + title: 'Security Update', + link: 'https://example.com/security/update', + severity: 'high', + scope: 'internal', + }, + }); + }); + + it(`should ${examples[2].description}`, async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'entity', + entityRef: ['entity:component:1'], + }, + payload: { + description: 'Here is your weekly update.', + link: undefined, + severity: 'low', + scope: undefined, + title: 'Weekly Update', + }, + }); + }); + + it(`should ${examples[3].description}`, async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: 'Version 2.0.0 is now available. Upgrade now!', + link: undefined, + severity: 'normal', + scope: 'public', + title: 'New Release Available', + }, + }); + }); + + it(`should ${examples[4].description}`, async () => { + const input = yaml.parse(examples[4].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'entity', + entityRef: ['entity:component:1'], + }, + payload: { + description: + 'A critical bug has been identified. Immediate action required.', + link: undefined, + scope: 'internal', + severity: 'critical', + title: 'Critical Bug Found', + }, + }); + }); + + it(`should ${examples[5].description}`, async () => { + const input = yaml.parse(examples[5].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'broadcast', + }, + payload: { + description: 'Server maintenance will occur tonight at 11 PM.', + link: undefined, + scope: 'internal', + severity: 'normal', + title: 'Server Maintenance Scheduled', + }, + }); + }); + + it(`should ${examples[6].description}`, async () => { + const input = yaml.parse(examples[6].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: 'New features have been deployed. Explore them now!', + link: undefined, + scope: undefined, + severity: 'normal', + title: 'New Feature Deployment', + }, + }); + }); + + it(`should ${examples[7].description}`, async () => { + const input = yaml.parse(examples[7].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: undefined, + link: undefined, + scope: 'internal', + severity: 'low', + title: 'Holiday Office Closure', + }, + }); + }); + + it(`should ${examples[8].description}`, async () => { + const input = yaml.parse(examples[8].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: + "Don't forget, the weekly meeting is scheduled for tomorrow.", + link: undefined, + scope: 'internal', + severity: undefined, + title: 'Reminder: Weekly Meeting Tomorrow', + }, + }); + }); + + it(`should ${examples[9].description}`, async () => { + const input = yaml.parse(examples[9].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + title: 'Important Announcement', + description: + 'Please read the latest announcement regarding the upcoming changes.', + link: undefined, + scope: undefined, + severity: 'high', + }, + }); + }); + + it(`should ${examples[10].description}`, async () => { + const input = yaml.parse(examples[10].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + title: 'Broadcast Notification', + description: 'This is a broadcast notification', + link: undefined, + scope: undefined, + severity: 'low', + }, + }); + }); + + it(`should ${examples[11].description}`, async () => { + const input = yaml.parse(examples[11].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'entity', + entityRef: ['entity:service1'], + }, + payload: { + title: 'Entity Notification', + description: 'This is a notification for entity service1', + link: undefined, + scope: undefined, + severity: 'normal', + }, + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.ts b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.ts new file mode 100644 index 0000000000..05bbd368f8 --- /dev/null +++ b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.ts @@ -0,0 +1,255 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Sends a notification with minimal options', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Test notification', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with entity recipients and link', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'entity', + entityRefs: ['entity:component:1'], + title: 'Security Update', + info: 'A security update has been applied. Please review.', + link: 'https://example.com/security/update', + severity: 'high', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with entity recipients and optional flag', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'entity', + entityRefs: ['entity:component:1'], + title: 'Weekly Update', + info: 'Here is your weekly update.', + severity: 'low', + optional: true, + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and custom scope', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'New Release Available', + info: 'Version 2.0.0 is now available. Upgrade now!', + severity: 'normal', + scope: 'public', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with entity recipients and custom severity', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'entity', + entityRefs: ['entity:component:1'], + title: 'Critical Bug Found', + info: 'A critical bug has been identified. Immediate action required.', + severity: 'critical', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with broadcast recipients and no link', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Server Maintenance Scheduled', + info: 'Server maintenance will occur tonight at 11 PM.', + severity: 'normal', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and optional flag', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'New Feature Deployment', + info: 'New features have been deployed. Explore them now!', + severity: 'normal', + optional: true, + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and no description', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Holiday Office Closure', + severity: 'low', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and no severity', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Reminder: Weekly Meeting Tomorrow', + info: "Don't forget, the weekly meeting is scheduled for tomorrow.", + scope: 'internal', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with broadcast recipients and no scope', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Important Announcement', + info: 'Please read the latest announcement regarding the upcoming changes.', + severity: 'high', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with optional parameters', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Broadcast Notification', + info: 'This is a broadcast notification', + severity: 'low', + optional: true, + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with entity recipients and optional set to false', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification to Entity', + input: { + recipients: 'entity', + entityRefs: ['entity:service1'], + title: 'Entity Notification', + info: 'This is a notification for entity service1', + severity: 'normal', + optional: false, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts index f50e178174..9646de0001 100644 --- a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts +++ b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts @@ -22,6 +22,7 @@ import { NotificationSeverity, } from '@backstage/plugin-notifications-common'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { examples } from './sendNotification.examples'; /** * @public @@ -42,6 +43,7 @@ export function createSendNotificationAction(options: { }>({ id: 'notification:send', description: 'Sends a notification using NotificationService', + examples, schema: { input: { type: 'object', diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 0db7584509..ed34f47a58 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.40-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.4.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.4.40-next.0 + +### Patch Changes + +- 449def7: Add examples for fetch:rails scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.4.39 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.39-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index c15815d2fa..8cbd5e1067 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", - "version": "0.4.39-next.1", + "version": "0.4.40-next.2", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", @@ -51,7 +51,8 @@ "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/types": "workspace:^", "command-exists": "^1.2.9", - "fs-extra": "^11.0.0" + "fs-extra": "^11.0.0", + "yaml": "^2.0.0" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts new file mode 100644 index 0000000000..37e678ab6a --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts @@ -0,0 +1,341 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const mockRailsTemplater = { run: jest.fn() }; +jest.mock('@backstage/plugin-scaffolder-node', () => ({ + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + fetchContents: jest.fn(), +})); +jest.mock('./railsNewRunner', () => { + return { + RailsNewRunner: jest.fn().mockImplementation(() => { + return mockRailsTemplater; + }), + }; +}); + +import { ContainerRunner, UrlReader } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { resolve as resolvePath } from 'path'; +import { createFetchRailsAction } from './index'; +import { fetchContents } from '@backstage/plugin-scaffolder-node'; +import { createMockDirectory } from '@backstage/backend-test-utils'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { examples } from './index.examples'; +import yaml from 'yaml'; + +describe('fetch:rails', () => { + const mockDir = createMockDirectory(); + const integrations = ScmIntegrations.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { host: 'dev.azure.com', token: 'tokenlols' }, + { host: 'myazurehostnotoken.com' }, + ], + }, + }), + ); + + const mockContext = createMockActionContext({ + input: { + url: 'https://rubyonrails.org/generator', + targetPath: 'something', + values: { + help: 'me', + }, + }, + templateInfo: { + baseUrl: 'somebase', + entityRef: 'template:default/myTemplate', + }, + workspacePath: mockDir.path, + }); + + const mockReader: UrlReader = { + readUrl: jest.fn(), + readTree: jest.fn(), + search: jest.fn(), + }; + const containerRunner: ContainerRunner = { + runContainer: jest.fn(), + }; + + const action = createFetchRailsAction({ + integrations, + reader: mockReader, + containerRunner, + allowedImageNames: ['foo/rails-custom-image'], + }); + + beforeEach(() => { + mockDir.setContent({ + result: '{}', + }); + jest.clearAllMocks(); + }); + + it(`should ${examples[0].description}`, async () => { + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[1].description}`, async () => { + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[2].description}`, async () => { + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[3].description}`, async () => { + let input; + try { + input = yaml.parse(examples[3].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[4].description}`, async () => { + let input; + try { + input = yaml.parse(examples[4].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[5].description}`, async () => { + let input; + try { + input = yaml.parse(examples[5].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[6].description}`, async () => { + let input; + try { + input = yaml.parse(examples[6].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[7].description}`, async () => { + let input; + try { + input = yaml.parse(examples[7].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[8].description}`, async () => { + let input; + try { + input = yaml.parse(examples[8].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[9].description}`, async () => { + let input; + try { + input = yaml.parse(examples[9].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.ts new file mode 100644 index 0000000000..4c77eb3c1b --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.ts @@ -0,0 +1,370 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Fetch and template a minimal Rails app', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: true, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: true, + api: true, + webpacker: 'react', + database: 'postgresql', + railsVersion: 'dev', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Fetch and template a Rails app with custom options', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + targetPath: 'custom-path', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: false, + api: false, + webpacker: 'vue', + database: 'mysql', + railsVersion: 'edge', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Fetch and template a Rails app with Docker image', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: true, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: true, + api: true, + webpacker: 'react', + database: 'postgresql', + railsVersion: 'dev', + }, + imageName: 'custom/rails-image', + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with different database and action mailer settings', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: true, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: true, + api: true, + webpacker: 'angular', + database: 'sqlite3', + railsVersion: 'master', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with full options including action mailer and active storage', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: false, + api: false, + webpacker: 'stimulus', + database: 'postgresql', + railsVersion: 'fromImage', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with API-only stack and custom template path', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: true, + api: true, + webpacker: 'elm', + database: 'mysql', + railsVersion: 'dev', + template: 'path/to/custom/template', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Fetch and template a Rails app with custom Webpack setup', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: false, + api: false, + webpacker: 'angular', + database: 'postgresql', + railsVersion: 'dev', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with specific Rails version and Action Mailer enabled', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: true, + api: true, + webpacker: 'react', + database: 'sqlite3', + railsVersion: 'master', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with specific database and Active Storage enabled', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: true, + api: true, + webpacker: 'vue', + database: 'postgresql', + railsVersion: 'fromImage', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with full options including database and skip options', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: false, + api: false, + webpacker: 'stimulus', + database: 'sqlite3', + railsVersion: 'dev', + }, + }, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts index 394d0fb02c..94a2a3539b 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts @@ -27,6 +27,7 @@ import { import { resolve as resolvePath } from 'path'; import { RailsNewRunner } from './railsNewRunner'; import { PassThrough } from 'stream'; +import { examples } from './index.examples'; /** * Creates the `fetch:rails` Scaffolder action. @@ -56,6 +57,7 @@ export function createFetchRailsAction(options: { id: 'fetch:rails', description: 'Downloads a template from the given `url` into the workspace, and runs a rails new generator on it.', + examples, schema: { input: { type: 'object', diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 29e8c17b04..c4421d314b 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.1.31-next.2 + +### Patch Changes + +- 93095ee: Make sure node-fetch is version 2.7.0 or greater +- 382e868: Added test cases for sentry:project:create examples +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## 0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.30-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index c0866f979d..f683e23d09 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.1.30-next.1", + "version": "0.1.31-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", @@ -46,7 +46,7 @@ "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "yaml": "^2.3.3" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.test.ts new file mode 100644 index 0000000000..3e31aef3bc --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.test.ts @@ -0,0 +1,232 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { registerMswTestHooks } from '@backstage/backend-test-utils'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { ActionContext } from '@backstage/plugin-scaffolder-node'; +import { JsonObject } from '@backstage/types'; +import { randomBytes } from 'crypto'; +import { setupServer } from 'msw/node'; +import { HttpResponse, http } from 'msw'; +import { createSentryCreateProjectAction } from './createProject'; +import yaml from 'yaml'; +import { examples } from './createProject.examples'; + +describe('sentry:project:create action', () => { + const worker = setupServer(); + registerMswTestHooks(worker); + + const createScaffolderConfig = (configData: JsonObject = {}) => ({ + config: new ConfigReader({ + scaffolder: { + ...configData, + }, + }), + }); + + const getActionContext = (): ActionContext<{ + organizationSlug: string; + teamSlug: string; + name: string; + slug?: string; + authToken?: string; + }> => + createMockActionContext({ + workspacePath: './dev/proj', + logger: jest.createMockFromModule('winston'), + input: { + organizationSlug: 'org', + teamSlug: 'team', + name: 'test project', + authToken: randomBytes(5).toString('hex'), + }, + }); + + it(`should ${examples[0].description}`, async () => { + expect.assertions(3); + + let input; + try { + input = yaml.parse(examples[0].example).steps[1].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${input.organizationSlug}/${input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer b15711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d4gf93`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: 'Scaffolded project B', + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler({ + ...actionContext, + input: { + ...actionContext.input, + ...input, + }, + }); + }); + + it(`should ${examples[0].description}`, async () => { + expect.assertions(3); + + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + actionContext.input = { ...actionContext.input, slug: 'project-slug' }; + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${input.organizationSlug}/${input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer a14711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d5df96`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: 'Scaffolded project A', + slug: 'scaff-proj-a', + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler({ + ...actionContext, + input: { + ...actionContext.input, + ...input, + }, + }); + }); + + it(`should ${examples[1].description}`, async () => { + expect.assertions(3); + + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + const sentryScaffolderConfigToken = randomBytes(5).toString('hex'); + const action = createSentryCreateProjectAction( + createScaffolderConfig({ + sentry: { + token: sentryScaffolderConfigToken, + }, + }), + ); + const actionContext = getActionContext(); + actionContext.input.authToken = undefined; + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${input.organizationSlug}/${input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer ${sentryScaffolderConfigToken}`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: 'Scaffolded project A', + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler({ + ...actionContext, + input: { + ...actionContext.input, + ...input, + }, + }); + }); + + it(`should ${examples[2].description}`, async () => { + expect.assertions(3); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${input.organizationSlug}/${input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer c16711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d6gf94`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: 'A very long name for the scaffolded project C that will generate a slug', + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler({ + ...actionContext, + input: { + ...actionContext.input, + ...input, + }, + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts index 9d4551c1b5..3af88a4663 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts @@ -50,4 +50,41 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Creates a Sentry project when no auth token is passed', + example: yaml.stringify({ + steps: [ + { + id: 'create-sentry-project', + action: 'sentry:project:create', + name: 'Create a Sentry project with provided project slug.', + input: { + organizationSlug: 'my-org', + teamSlug: 'team-a', + name: 'Scaffolded project A', + }, + }, + ], + }), + }, + { + description: + 'Creates a Sentry project with a long project name and automatically generated slug.', + example: yaml.stringify({ + steps: [ + { + id: 'create-sentry-project', + action: 'sentry:project:create', + name: 'Create a Sentry project with a long name and no slug provided.', + input: { + organizationSlug: 'my-org', + teamSlug: 'team-c', + name: 'A very long name for the scaffolded project C that will generate a slug', + authToken: + 'c16711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d6gf94', + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts index 158b7db4ae..48c437d2a4 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { ConfigReader } from '@backstage/config'; import { InputError } from '@backstage/errors'; @@ -27,7 +27,7 @@ import { createSentryCreateProjectAction } from './createProject'; describe('sentry:project:create action', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); const createScaffolderConfig = (configData: JsonObject = {}) => ({ config: new ConfigReader({ diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 4e99b51284..4833302170 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.2 + - @backstage/types@1.1.1 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.1 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.0 + +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-node-test-utils@0.1.9 + - @backstage/types@1.1.1 + ## 0.3.6-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 76158fdc01..36aed409cc 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.3.6-next.1", + "version": "0.3.7-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index a4df9e72e9..0ed359768e 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,140 @@ # @backstage/plugin-scaffolder-backend +## 1.23.1-next.2 + +### Patch Changes + +- c544f81: Add support for status filtering in scaffolder tasks endpoint +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.1-next.2 + - @backstage/backend-tasks@0.5.28-next.2 + - @backstage/plugin-catalog-node@1.12.5-next.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.2 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 1.23.1-next.1 + +### Patch Changes + +- ef87e06: Fix scaffolder action `catalog:write` to write to directories that don't already exist +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.1 + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/plugin-permission-node@0.8.1-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.1 + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.1 + - @backstage/backend-tasks@0.5.28-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-node@0.4.18-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 1.23.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 1.23.0 + +### Minor Changes + +- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- b9451dd: Updated `catalog:write` scaffolder action to show correct file path location in log message +- ff1bb4c: Added a documentation how to use checkpoints +- da90cce: Updated dependency `esbuild` to `^0.21.0`. +- 62d1fe3: Fix user entity not being fetched for scaffolder dry runner +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.14 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.12 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.23.0-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index a3beee2b53..1e60d5b026 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -312,7 +312,7 @@ export const createPublishGitlabMergeRequestAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'update' | 'delete' | 'create' | undefined; + commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; @@ -427,7 +427,7 @@ export class DatabaseTaskStore implements TaskStore { // (undocumented) heartbeatTask(taskId: string): Promise; // (undocumented) - list(options: { createdBy?: string }): Promise<{ + list(options: { createdBy?: string; status?: TaskStatus_2 }): Promise<{ tasks: SerializedTask_2[]; }>; // (undocumented) @@ -646,7 +646,7 @@ export interface TaskStore { // (undocumented) heartbeatTask(taskId: string): Promise; // (undocumented) - list?(options: { createdBy?: string }): Promise<{ + list?(options: { createdBy?: string; status?: TaskStatus }): Promise<{ tasks: SerializedTask[]; }>; // (undocumented) diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 10d827762e..974125ad94 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "1.23.0-next.2", + "version": "1.23.1-next.2", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.examples.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.examples.test.ts index e6b4bcde47..f900e87a1d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.examples.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.examples.test.ts @@ -55,8 +55,8 @@ describe('catalog:write', () => { input: yaml.parse(examples[0].example).steps[0].input, }); - expect(fsMock.writeFile).toHaveBeenCalledTimes(1); - expect(fsMock.writeFile).toHaveBeenCalledWith( + expect(fsMock.outputFile).toHaveBeenCalledTimes(1); + expect(fsMock.outputFile).toHaveBeenCalledWith( resolvePath(mockContext.workspacePath, 'catalog-info.yaml'), yaml.stringify(entity), ); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts index 658e4365bf..469b4d5c6d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts @@ -59,8 +59,8 @@ describe('catalog:write', () => { }, }); - expect(fsMock.writeFile).toHaveBeenCalledTimes(1); - expect(fsMock.writeFile).toHaveBeenCalledWith( + expect(fsMock.outputFile).toHaveBeenCalledTimes(1); + expect(fsMock.outputFile).toHaveBeenCalledWith( resolvePath(mockContext.workspacePath, 'catalog-info.yaml'), yaml.stringify(entity), ); @@ -88,8 +88,8 @@ describe('catalog:write', () => { }, }); - expect(fsMock.writeFile).toHaveBeenCalledTimes(1); - expect(fsMock.writeFile).toHaveBeenCalledWith( + expect(fsMock.outputFile).toHaveBeenCalledTimes(1); + expect(fsMock.outputFile).toHaveBeenCalledWith( resolvePath(mockContext.workspacePath, 'some-dir/entity-info.yaml'), yaml.stringify(entity), ); @@ -118,8 +118,8 @@ describe('catalog:write', () => { 'backstage.io/source-template': 'template:default/test-skeleton', }; - expect(fsMock.writeFile).toHaveBeenCalledTimes(1); - expect(fsMock.writeFile).toHaveBeenCalledWith( + expect(fsMock.outputFile).toHaveBeenCalledTimes(1); + expect(fsMock.outputFile).toHaveBeenCalledWith( resolvePath(mockContext.workspacePath, 'catalog-info.yaml'), yaml.stringify(expectedEntity), ); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts index a957adb71a..29ce6c986d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts @@ -54,7 +54,7 @@ export function createCatalogWriteAction() { const path = filePath ?? 'catalog-info.yaml'; ctx.logger.info(`Writing ${path}`); - await fs.writeFile( + await fs.outputFile( resolveSafeChildPath(ctx.workspacePath, path), yaml.stringify({ ...entity, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts b/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts index fd5fdd49e8..5d037b44b6 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts @@ -22,56 +22,66 @@ import * as bitbucketServer from '@backstage/plugin-scaffolder-backend-module-bi import * as gerrit from '@backstage/plugin-scaffolder-backend-module-gerrit'; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubActionsDispatchAction = github.createGithubActionsDispatchAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubDeployKeyAction = github.createGithubDeployKeyAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubEnvironmentAction = github.createGithubEnvironmentAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubIssuesLabelAction = github.createGithubIssuesLabelAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export type CreateGithubPullRequestActionOptions = github.CreateGithubPullRequestActionOptions; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubRepoCreateAction = github.createGithubRepoCreateAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubRepoPushAction = github.createGithubRepoPushAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubWebhookAction = github.createGithubWebhookAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createPublishGithubAction = github.createPublishGithubAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createPublishGithubPullRequestAction = github.createPublishGithubPullRequestAction; @@ -83,46 +93,54 @@ export const createPublishBitbucketAction = bitbucket.createPublishBitbucketAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead */ export const createPublishBitbucketCloudAction = bitbucketCloud.createPublishBitbucketCloudAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerAction = bitbucketServer.createPublishBitbucketServerAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerPullRequestAction = bitbucketServer.createPublishBitbucketServerPullRequestAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-azure instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-azure` instead */ export const createPublishAzureAction = azure.createPublishAzureAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gerrit instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gerrit` instead */ export const createPublishGerritAction = gerrit.createPublishGerritAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gerrit instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gerrit` instead */ export const createPublishGerritReviewAction = gerrit.createPublishGerritReviewAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gitlab instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gitlab` instead */ export const createPublishGitlabAction = gitlab.createPublishGitlabAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gitlab instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gitlab` instead */ export const createPublishGitlabMergeRequestAction = gitlab.createPublishGitlabMergeRequestAction; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts index f4fae0715b..78a362b5c7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts @@ -95,6 +95,33 @@ describe('DatabaseTaskStore', () => { expect(tasks[0].id).toBeDefined(); }); + it('should list filtered created tasks by status', async () => { + const { store } = await createStore(); + + const { taskId } = await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'him', + }); + + const message = `This task was marked as stale as it exceeded its timeout`; + await store.completeTask({ + taskId, + status: 'cancelled', + eventBody: { message }, + }); + + const { tasks } = await store.list({ status: 'open' }); + expect(tasks.length).toBe(1); + expect(tasks[0].createdBy).toBe('him'); + expect(tasks[0].status).toBe('open'); + expect(tasks[0].id).toBeDefined(); + }); + it('should sent an event to start cancelling the task', async () => { const { store } = await createStore(); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index fe62572af9..ba675b2cc7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -22,19 +22,19 @@ import { Knex } from 'knex'; import { v4 as uuid } from 'uuid'; import { TaskStore, - TaskStoreEmitOptions, - TaskStoreListEventsOptions, TaskStoreCreateTaskOptions, TaskStoreCreateTaskResult, - TaskStoreShutDownTaskOptions, + TaskStoreEmitOptions, + TaskStoreListEventsOptions, TaskStoreRecoverTaskOptions, + TaskStoreShutDownTaskOptions, } from './types'; import { - SerializedTaskEvent, SerializedTask, - TaskStatus, + SerializedTaskEvent, TaskEventType, TaskSecrets, + TaskStatus, } from '@backstage/plugin-scaffolder-node'; import { DateTime, Duration } from 'luxon'; import { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common'; @@ -182,6 +182,7 @@ export class DatabaseTaskStore implements TaskStore { async list(options: { createdBy?: string; + status?: TaskStatus; }): Promise<{ tasks: SerializedTask[] }> { const queryBuilder = this.db('tasks'); @@ -191,6 +192,10 @@ export class DatabaseTaskStore implements TaskStore { }); } + if (options.status) { + queryBuilder.where({ status: options.status }); + } + const results = await queryBuilder.orderBy('created_at', 'desc').select(); const tasks = results.map(result => ({ diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts index f4946e6652..d17fb33b3b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -20,13 +20,14 @@ import { JsonObject, JsonValue, Observable } from '@backstage/types'; import { Logger } from 'winston'; import ObservableImpl from 'zen-observable'; import { - TaskSecrets, SerializedTask, SerializedTaskEvent, TaskBroker, TaskBrokerDispatchOptions, TaskCompletionState, TaskContext, + TaskSecrets, + TaskStatus, } from '@backstage/plugin-scaffolder-node'; import { InternalTaskSecrets, TaskStore } from './types'; import { readDuration } from './helper'; @@ -279,13 +280,17 @@ export class StorageTaskBroker implements TaskBroker { async list(options?: { createdBy?: string; + status?: TaskStatus; }): Promise<{ tasks: SerializedTask[] }> { if (!this.storage.list) { throw new Error( 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks', ); } - return await this.storage.list({ createdBy: options?.createdBy }); + return await this.storage.list({ + createdBy: options?.createdBy, + status: options?.status, + }); } private deferredDispatch = defer(); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts index 0e0ebd706b..89bcce3cc9 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts @@ -14,20 +14,20 @@ * limitations under the License. */ -import { JsonValue, JsonObject, HumanDuration } from '@backstage/types'; +import { HumanDuration, JsonObject, JsonValue } from '@backstage/types'; import { TaskSpec, TaskStep } from '@backstage/plugin-scaffolder-common'; -import { TaskSecrets } from '@backstage/plugin-scaffolder-node'; import { - TemplateAction, - TaskStatus as _TaskStatus, - TaskCompletionState as _TaskCompletionState, SerializedTask as _SerializedTask, - TaskEventType as _TaskEventType, SerializedTaskEvent as _SerializedTaskEvent, - TaskBrokerDispatchResult as _TaskBrokerDispatchResult, - TaskBrokerDispatchOptions as _TaskBrokerDispatchOptions, - TaskContext as _TaskContext, TaskBroker as _TaskBroker, + TaskBrokerDispatchOptions as _TaskBrokerDispatchOptions, + TaskBrokerDispatchResult as _TaskBrokerDispatchResult, + TaskCompletionState as _TaskCompletionState, + TaskContext as _TaskContext, + TaskEventType as _TaskEventType, + TaskSecrets, + TaskStatus as _TaskStatus, + TemplateAction, } from '@backstage/plugin-scaffolder-node'; /** @@ -190,7 +190,10 @@ export interface TaskStore { tasks: { taskId: string }[]; }>; - list?(options: { createdBy?: string }): Promise<{ tasks: SerializedTask[] }>; + list?(options: { + createdBy?: string; + status?: TaskStatus; + }): Promise<{ tasks: SerializedTask[] }>; emitLogEvent(options: TaskStoreEmitOptions): Promise; diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index af06fc4034..01a2fba6e8 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -432,10 +432,11 @@ describe('createRouter', () => { }); const response = await request(app).get( - `/v2/tasks?createdBy=user:default/foo`, + `/v2/tasks?createdBy=user:default/foo&status=completed`, ); expect(taskBroker.list).toHaveBeenCalledWith({ createdBy: 'user:default/foo', + status: 'completed', }); expect(response.status).toEqual(200); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 769a042a78..a25731ce45 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -15,10 +15,10 @@ */ import { + createLegacyAuthAdapters, HostDiscovery, PluginDatabaseManager, UrlReader, - createLegacyAuthAdapters, } from '@backstage/backend-common'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { CatalogApi } from '@backstage/catalog-client'; @@ -35,22 +35,22 @@ import { ScmIntegrations } from '@backstage/integration'; import { HumanDuration, JsonObject, JsonValue } from '@backstage/types'; import { TaskSpec, + TemplateEntityStepV1beta3, TemplateEntityV1beta3, templateEntityV1beta3Validator, TemplateParametersV1beta3, - TemplateEntityStepV1beta3, } from '@backstage/plugin-scaffolder-common'; import { RESOURCE_TYPE_SCAFFOLDER_ACTION, RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, scaffolderActionPermissions, + scaffolderTaskPermissions, scaffolderTemplatePermissions, taskCancelPermission, taskCreatePermission, taskReadPermission, templateParameterReadPermission, templateStepReadPermission, - scaffolderTaskPermissions, } from '@backstage/plugin-scaffolder-common/alpha'; import express from 'express'; import Router from 'express-promise-router'; @@ -58,8 +58,9 @@ import { validate } from 'jsonschema'; import { Logger } from 'winston'; import { z } from 'zod'; import { - TemplateAction, TaskBroker, + TaskStatus, + TemplateAction, TemplateFilter, TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; @@ -587,8 +588,17 @@ export async function createRouter( ); } + const [statusQuery] = [req.query.status].flat(); + if ( + typeof statusQuery !== 'string' && + typeof statusQuery !== 'undefined' + ) { + throw new InputError('status query parameter must be a string'); + } + const tasks = await taskBroker.list({ createdBy: userEntityRef, + status: statusQuery ? (statusQuery as TaskStatus) : undefined, }); res.status(200).json(tasks); diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 12f3f9e235..4810656ef4 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder-common +## 1.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## 1.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## 1.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + ## 1.5.3 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 3e56510daf..949a831906 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-common", - "version": "1.5.3", + "version": "1.5.5-next.1", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index 9104fbcb26..c7d37fb0c8 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@0.4.5-next.2 + - @backstage/plugin-scaffolder-node@0.4.9-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/types@1.1.1 + +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.1 + - @backstage/backend-test-utils@0.4.5-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.1 + +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-test-utils@0.4.5-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## 0.1.9 + +### Patch Changes + +- 54429b5: Filename and imports correction for mockActionContext.ts +- Updated dependencies + - @backstage/backend-test-utils@0.4.4 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/types@1.1.1 + ## 0.1.9-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index d361d0ae1d..707ffa1388 100644 --- a/plugins/scaffolder-node-test-utils/package.json +++ b/plugins/scaffolder-node-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node-test-utils", - "version": "0.1.9-next.1", + "version": "0.1.10-next.2", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index f67c8c8cda..42fc13a644 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/plugin-scaffolder-node +## 0.4.9-next.2 + +### Patch Changes + +- c544f81: Add support for status filtering in scaffolder tasks endpoint +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.4.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.4.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.4 + +## 0.4.8 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers +- 0b52438: Serialization of the scaffolder workspace into GCP bucket +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.8-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md index 66e8ccd678..515a169cb2 100644 --- a/plugins/scaffolder-node/api-report.md +++ b/plugins/scaffolder-node/api-report.md @@ -315,7 +315,7 @@ export interface TaskBroker { // (undocumented) get(taskId: string): Promise; // (undocumented) - list?(options?: { createdBy?: string }): Promise<{ + list?(options?: { createdBy?: string; status?: TaskStatus }): Promise<{ tasks: SerializedTask[]; }>; // (undocumented) diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 079eebfb00..6e84b278c2 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.4.8-next.1", + "version": "0.4.9-next.2", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-node/src/tasks/types.ts b/plugins/scaffolder-node/src/tasks/types.ts index a2adb97b9c..8324e352f2 100644 --- a/plugins/scaffolder-node/src/tasks/types.ts +++ b/plugins/scaffolder-node/src/tasks/types.ts @@ -180,5 +180,8 @@ export interface TaskBroker { get(taskId: string): Promise; - list?(options?: { createdBy?: string }): Promise<{ tasks: SerializedTask[] }>; + list?(options?: { + createdBy?: string; + status?: TaskStatus; + }): Promise<{ tasks: SerializedTask[] }>; } diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index a1ed542bd5..1661f3d1c7 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,87 @@ # @backstage/plugin-scaffolder-react +## 1.11.0-next.2 + +### Patch Changes + +- 072c00c: Fixed a bug in `DefaultTableOutputs` where output elements overlapped on smaller screen sizes +- 04759f2: Fix null check in `isJsonObject` utility function for scaffolder review state component +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/plugin-permission-react@0.4.25-next.1 + - @backstage/plugin-scaffolder-common@1.5.5-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## 1.11.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/plugin-permission-react@0.4.25-next.0 + - @backstage/plugin-scaffolder-common@1.5.5-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## 1.11.0-next.0 + +### Minor Changes + +- 8839381: Add scaffolder option to display object items in separate rows on review page + +### Patch Changes + +- d0e95a7: Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in `FormProps` +- 4670f06: support `ajv-errors` for scaffolder validation to allow for customizing the error messages +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + +## 1.10.0 + +### Minor Changes + +- 354e68c: Improve validation error display text in scaffolder +- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- 4d7e11f: disables rendering of output box if no output is returned +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.10.0-next.2 ### Patch Changes diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index a14490b80c..a19a656d17 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -128,7 +128,7 @@ export interface FieldExtensionUiSchema // @public export type FormProps = Pick< FormProps_2, - 'transformErrors' | 'noHtml5Validate' + 'transformErrors' | 'noHtml5Validate' | 'uiSchema' | 'formContext' >; // @public diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 36ee0870fc..b47bbd731f 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.10.0-next.2", + "version": "1.11.0-next.2", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", @@ -78,6 +78,7 @@ "@rjsf/validator-ajv8": "5.18.5", "@types/json-schema": "^7.0.9", "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "ajv-errors": "^3.0.0", "classnames": "^2.2.6", "flatted": "3.3.1", "humanize-duration": "^3.25.1", diff --git a/plugins/scaffolder-react/src/components/types.ts b/plugins/scaffolder-react/src/components/types.ts index 597998bac4..d5d317015d 100644 --- a/plugins/scaffolder-react/src/components/types.ts +++ b/plugins/scaffolder-react/src/components/types.ts @@ -32,7 +32,7 @@ export type TemplateGroupFilter = { */ export type FormProps = Pick< SchemaFormProps, - 'transformErrors' | 'noHtml5Validate' + 'transformErrors' | 'noHtml5Validate' | 'uiSchema' | 'formContext' >; /** 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..194c5f3e77 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx @@ -69,6 +69,9 @@ describe('ReviewState', () => { const formState = { name: 'John Doe', test: 'bob', + nest: { + foo: 'bar', + }, }; const schemas: ParsedTemplateSchema[] = [ @@ -85,6 +88,20 @@ describe('ReviewState', () => { }, }, }, + nest: { + type: 'object', + properties: { + foo: { + type: 'string', + 'ui:widget': 'password', + 'ui:backstage': { + review: { + show: false, + }, + }, + }, + }, + }, }, }, schema: {}, @@ -99,12 +116,16 @@ describe('ReviewState', () => { ); expect(getAllByRole('row').length).toEqual(1); expect(queryByRole('row', { name: 'Name ******' })).not.toBeInTheDocument(); + expect(queryByRole('row', { name: 'Foo ******' })).not.toBeInTheDocument(); }); it('should allow for masking an option with a set text', () => { const formState = { name: 'John Doe', test: 'bob', + nest: { + foo: 'bar', + }, }; const schemas: ParsedTemplateSchema[] = [ @@ -121,6 +142,20 @@ describe('ReviewState', () => { }, }, }, + nest: { + type: 'object', + properties: { + foo: { + type: 'string', + 'ui:widget': 'password', + 'ui:backstage': { + review: { + mask: 'lols', + }, + }, + }, + }, + }, }, }, schema: {}, @@ -135,11 +170,15 @@ describe('ReviewState', () => { ); expect(getByRole('row', { name: 'Name lols' })).toBeInTheDocument(); + expect(getByRole('row', { name: 'Foo lols' })).toBeInTheDocument(); }); it('should display enum label from enumNames', async () => { const formState = { name: 'type2', + nest: { + foo: 'type2', + }, }; const schemas: ParsedTemplateSchema[] = [ @@ -153,6 +192,17 @@ describe('ReviewState', () => { enum: ['type1', 'type2', 'type3'], enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], }, + nest: { + type: 'object', + properties: { + foo: { + type: 'string', + default: 'type1', + enum: ['type1', 'type2', 'type3'], + enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], + }, + }, + }, }, }, schema: {}, @@ -169,6 +219,7 @@ describe('ReviewState', () => { expect( queryByRole('row', { name: 'Name Label-type2' }), ).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Foo Label-type2' })).toBeInTheDocument(); }); it('should display enum value if no corresponding enumNames', async () => { @@ -202,4 +253,159 @@ describe('ReviewState', () => { expect(queryByRole('row', { name: 'Name type4' })).toBeInTheDocument(); }); + + it('should display object in separate rows', async () => { + const formState = { + name: { + foo: 'type3', + bar: 'type4', + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + properties: { + foo: { + type: 'string', + default: 'type1', + }, + bar: { + type: 'string', + default: 'type2', + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); + }); + + it('should display nested objects in separate rows', async () => { + const formState = { + name: { + foo: 'type3', + bar: 'type4', + example: { + test: 'type6', + }, + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + properties: { + foo: { + type: 'string', + default: 'type1', + }, + bar: { + type: 'string', + default: 'type2', + }, + example: { + type: 'object', + properties: { + test: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Test type6' })).toBeInTheDocument(); + }); + + it('should display partially nested objects', async () => { + const formState = { + name: { + foo: 'type3', + bar: 'type4', + example: { + test: 'type6', + }, + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + properties: { + foo: { + type: 'string', + default: 'type1', + }, + bar: { + type: 'string', + default: 'type2', + }, + example: { + type: 'object', + 'ui:backstage': { + review: { + explode: false, + }, + }, + properties: { + test: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Test type6' })).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..d87584afff 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 } from '@backstage/types'; +import { JsonObject, JsonValue } from '@backstage/types'; import { Draft07 as JSONSchema } from 'json-schema-library'; import { ParsedTemplateSchema } from '../../hooks/useTemplateSchema'; +import { isJsonObject, getLastKey } from './util'; /** * The props for the {@link ReviewState} component. @@ -28,6 +29,55 @@ export type ReviewStateProps = { formState: JsonObject; }; +function processSchema( + key: string, + value: JsonValue | undefined, + schema: ParsedTemplateSchema, + formState: JsonObject, +): [string, JsonValue | undefined][] { + const parsedSchema = new JSONSchema(schema.mergedSchema); + const definitionInSchema = parsedSchema.getSchema({ + pointer: `#/${key}`, + data: formState, + }); + + if (definitionInSchema) { + const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; + if (backstageReviewOptions) { + if (backstageReviewOptions.mask) { + return [[getLastKey(key), backstageReviewOptions.mask]]; + } + if (backstageReviewOptions.show === false) { + return []; + } + } + + if (definitionInSchema['ui:widget'] === 'password') { + return [[getLastKey(key), '******']]; + } + + if (definitionInSchema.enum && definitionInSchema.enumNames) { + return [ + [ + getLastKey(key), + definitionInSchema.enumNames[ + definitionInSchema.enum.indexOf(value) + ] || value, + ], + ]; + } + + if (backstageReviewOptions?.explode !== false && isJsonObject(value)) { + // Recurse nested objects + return Object.entries(value).flatMap(([nestedKey, nestedValue]) => + processSchema(`${key}/${nestedKey}`, nestedValue, schema, formState), + ); + } + } + + return [[getLastKey(key), value]]; +} + /** * The component used by the {@link Stepper} to render the review step. * @alpha @@ -35,42 +85,11 @@ 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({ - pointer: `#/${key}`, - data: props.formState, - }); - - if (definitionInSchema) { - const backstageReviewOptions = - definitionInSchema['ui:backstage']?.review; - - if (backstageReviewOptions) { - if (backstageReviewOptions.mask) { - return [key, backstageReviewOptions.mask]; - } - if (backstageReviewOptions.show === false) { - return []; - } - } - - if (definitionInSchema['ui:widget'] === 'password') { - return [key, '******']; - } - - if (definitionInSchema.enum && definitionInSchema.enumNames) { - return [ - key, - definitionInSchema.enumNames[ - definitionInSchema.enum.indexOf(value) - ] || value, - ]; - } - } + return processSchema(key, value, step, props.formState); } - return [key, value]; + return [[key, value]]; }) .filter(prop => prop.length > 0), ); 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..649d0c3160 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts @@ -0,0 +1,78 @@ +/* + * 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 { isJsonObject, getLastKey } from './util'; + +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 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); + }); + + it('should return false for null values', () => { + expect(isJsonObject(null)).toBe(false); + }); +}); + +describe('getLastKey', () => { + it('should return the last part of a simple key', () => { + expect(getLastKey('simple')).toBe('simple'); + }); + + it('should return the last part of a nested key', () => { + expect(getLastKey('parent/child')).toBe('child'); + }); + + it('should return the last part of a deeply nested key', () => { + expect(getLastKey('grandparent/parent/child')).toBe('child'); + }); + + it('should handle keys with trailing slash', () => { + expect(getLastKey('parent/child/')).toBe(''); + }); + + it('should handle empty string', () => { + expect(getLastKey('')).toBe(''); + }); + + it('should handle keys with multiple consecutive slashes', () => { + expect(getLastKey('parent//child')).toBe('child'); + }); + + it('should handle keys with only slashes', () => { + expect(getLastKey('////')).toBe(''); + }); + + it('should handle keys with spaces', () => { + expect(getLastKey('parent/child with spaces')).toBe('child with spaces'); + }); + + it('should handle keys with special characters', () => { + expect(getLastKey('parent/child@!#$%^&*()')).toBe('child@!#$%^&*()'); + }); +}); diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts new file mode 100644 index 0000000000..d2caf71964 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts @@ -0,0 +1,27 @@ +/* + * 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 { JsonObject, JsonValue } from '@backstage/types'; + +export function isJsonObject(value?: JsonValue): value is JsonObject { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +// Helper function to get the last part of the key +export function getLastKey(key: string): string { + const parts = key.split('/'); + return parts[parts.length - 1]; +} diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx index d7e271f8b3..78aef3428f 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx @@ -392,6 +392,46 @@ describe('Stepper', () => { expect(getByText('invalid postcode')).toBeInTheDocument(); }); + it('should render ajv-errors message', async () => { + const manifest: TemplateParameterSchema = { + steps: [ + { + title: 'Step 1', + schema: { + properties: { + postcode: { + type: 'string', + pattern: '[A-Z][0-9][A-Z] [0-9][A-Z][0-9]', + }, + }, + errorMessage: { + properties: { + postcode: 'invalid postcode', + }, + }, + }, + }, + ], + title: 'transformErrors Form Test', + }; + + const { getByText, getByRole } = await renderInTestApp( + + + , + ); + + await fireEvent.change(getByRole('textbox', { name: 'postcode' }), { + target: { value: 'invalid' }, + }); + + await act(async () => { + await fireEvent.click(getByRole('button', { name: 'Review' })); + }); + + expect(getByText('invalid postcode')).toBeInTheDocument(); + }); + it('should grab the initial formData from the query', async () => { const manifest: TemplateParameterSchema = { steps: [ @@ -509,6 +549,66 @@ describe('Stepper', () => { }); }); + it('should allow overrides to the uiSchema and formContext correctly', async () => { + const manifest: TemplateParameterSchema = { + title: 'Custom Fields', + steps: [ + { + title: 'Test', + schema: { + properties: { + name: { + type: 'string', + 'ui:placeholder': 'Enter your name', + }, + age: { + type: 'number', + 'ui:placeholder': 'Enter your age', + }, + }, + }, + }, + ], + }; + + const uiSchema = { + name: { + 'ui:readonly': true, + 'ui:placeholder': 'Should be overwritten', + }, + }; + + const formContext = { + readOnlyAsDisabled: true, + }; + + const { getByRole } = await renderInTestApp( + + + , + ); + + expect(getByRole('textbox', { name: 'name' })).toHaveValue('Some Name'); + expect(getByRole('textbox', { name: 'name' })).toBeDisabled(); + expect(getByRole('textbox', { name: 'name' })).toHaveAttribute( + 'placeholder', + 'Enter your name', + ); + + expect(getByRole('spinbutton', { name: 'age' })).toHaveValue(40); + expect(getByRole('spinbutton', { name: 'age' })).toBeEnabled(); + expect(getByRole('spinbutton', { name: 'age' })).toHaveAttribute( + 'placeholder', + 'Enter your age', + ); + }); + describe('Scaffolder Layouts', () => { it('should render the step in the scaffolder layout', async () => { const ScaffolderLayout: LayoutTemplate = ({ properties }) => ( diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 269b6a11d5..3a8858144b 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -35,7 +35,7 @@ import { } from './createAsyncValidators'; import { ReviewState, type ReviewStateProps } from '../ReviewState'; import { useTemplateSchema, useFormDataFromQuery } from '../../hooks'; -import validator from '@rjsf/validator-ajv8'; +import { customizeValidator } from '@rjsf/validator-ajv8'; import { useTransformSchemaToProps } from '../../hooks/useTransformSchemaToProps'; import { hasErrors } from './utils'; import * as FieldOverrides from './FieldOverrides'; @@ -50,6 +50,11 @@ import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { ErrorListTemplate } from './ErrorListTemplate'; import { makeStyles } from '@material-ui/core/styles'; import { PasswordWidget } from '../PasswordWidget/PasswordWidget'; +import ajvErrors from 'ajv-errors'; +import { merge } from 'lodash'; + +const validator = customizeValidator(); +ajvErrors(validator.ajv); const useStyles = makeStyles(theme => ({ backButton: { @@ -189,6 +194,14 @@ export const Stepper = (stepperProps: StepperProps) => { setFormState(current => ({ ...current, ...formData })); }; + const { + formContext: propFormContext, + uiSchema: propUiSchema, + ...restFormProps + } = props.formProps ?? {}; + + const mergedUiSchema = merge({}, propUiSchema, currentStep?.uiSchema); + return ( <> {isValidating && } @@ -225,9 +238,9 @@ export const Stepper = (stepperProps: StepperProps) => { validator={validator} extraErrors={errors as unknown as ErrorSchema} formData={formState} - formContext={{ formData: formState }} + formContext={{ ...propFormContext, formData: formState }} schema={currentStep.schema} - uiSchema={currentStep.uiSchema} + uiSchema={mergedUiSchema} onSubmit={handleNext} fields={fields} showErrorList="top" @@ -237,7 +250,7 @@ export const Stepper = (stepperProps: StepperProps) => { experimental_defaultFormStateBehavior={{ allOf: 'populateDefaults', }} - {...(props.formProps ?? {})} + {...restFormProps} >
+ } + /> + ); +}; + +export const handleMetaRedirects = ( + navigate: (to: string) => void, + entityName: string, +): Transformer => { + const redirectAfterMs = 4000; + const determineRedirectURL = (metaUrl: string) => { + const normalizedCurrentUrl = normalizeUrl(window.location.href); + // If metaUrl is relative, it will be resolved with base href. If it is absolute, it will replace the base href when creating URL object. + const absoluteRedirectObj = new URL(metaUrl, normalizedCurrentUrl); + const isExternalRedirect = + absoluteRedirectObj.hostname !== window.location.hostname; + + if (isExternalRedirect) { + const currentTechDocPath = window.location.pathname; + const indexOfSiteHome = currentTechDocPath.indexOf(entityName); + const siteHomePath = currentTechDocPath.slice( + 0, + indexOfSiteHome + entityName.length, + ); + return siteHomePath; + } + // The navigate function from dom.tsx is a wrapper around react-router navigate function that helps absolute url redirects. + return absoluteRedirectObj.href; + }; + + return dom => { + for (const elem of Array.from(dom.querySelectorAll('meta'))) { + if (elem.getAttribute('http-equiv') === 'refresh') { + const metaContentParameters = elem + .getAttribute('content') + ?.split('url='); + if (!metaContentParameters || metaContentParameters.length < 2) { + continue; + } + const metaUrl = metaContentParameters[1]; + const redirectURL = determineRedirectURL(metaUrl); + const container = document.createElement('div'); + + renderReactElement( + navigate(redirectURL)} + autoHideDuration={redirectAfterMs} + />, + container, + ); + document.body.appendChild(container); + + setTimeout(() => { + navigate(redirectURL); + }, redirectAfterMs); + + return dom; + } + } + return dom; + }; +}; diff --git a/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx b/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx index ed5fbba085..e45d66c676 100644 --- a/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx +++ b/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx @@ -81,4 +81,44 @@ describe('Transformers > Html', () => { expect(iframes).toHaveLength(1); expect(iframes[0].src).toMatch('docs.google.com'); }); + + it('should return a function that allows refresh meta tags', async () => { + const { result } = renderHook(() => useSanitizerTransformer(), { wrapper }); + + const dirtyDom = document.createElement('html'); + dirtyDom.innerHTML = ` + + + + `; + const cleanDom = await result.current(dirtyDom); // calling html transformer + + const metaTags = Array.from( + cleanDom.querySelectorAll('meta'), + ); + + expect(metaTags).toHaveLength(1); + expect(metaTags[0].getAttribute('http-equiv')).toEqual('refresh'); + expect(metaTags[0].getAttribute('content')).toEqual( + '0;url=https://test.com', + ); + }); + + it('should return a function that does not allow non-refresh meta tags', async () => { + const { result } = renderHook(() => useSanitizerTransformer(), { wrapper }); + + const dirtyDom = document.createElement('html'); + dirtyDom.innerHTML = ` + + + + `; + const cleanDom = await result.current(dirtyDom); // calling html transformer + + const metaTags = Array.from( + cleanDom.querySelectorAll('meta'), + ); + + expect(metaTags).toHaveLength(0); + }); }); diff --git a/plugins/techdocs/src/reader/transformers/html/transformer.ts b/plugins/techdocs/src/reader/transformers/html/transformer.ts index 61498a37b0..4938a36648 100644 --- a/plugins/techdocs/src/reader/transformers/html/transformer.ts +++ b/plugins/techdocs/src/reader/transformers/html/transformer.ts @@ -44,17 +44,39 @@ export const useSanitizerTransformer = (): Transformer => { const hosts = config?.getOptionalStringArray('allowedIframeHosts'); DOMPurify.addHook('beforeSanitizeElements', removeUnsafeLinks); - const tags = ['link']; + const tags = ['link', 'meta']; if (hosts) { tags.push('iframe'); DOMPurify.addHook('beforeSanitizeElements', removeUnsafeIframes(hosts)); } + // Only allow meta tags if they are used for refreshing the page. They are required for the redirect feature. + DOMPurify.addHook('uponSanitizeElement', (currNode, data) => { + if (data.tagName === 'meta') { + const isMetaRefreshTag = + currNode.getAttribute('http-equiv') === 'refresh' && + currNode.getAttribute('content')?.includes('url='); + if (!isMetaRefreshTag) { + currNode.parentNode?.removeChild(currNode); + } + } + }); + + // Only allow http-equiv and content attributes on meta tags. They are required for the redirect feature. + DOMPurify.addHook('uponSanitizeAttribute', (currNode, data) => { + if (currNode.tagName !== 'meta') { + if (data.attrName === 'http-equiv' || data.attrName === 'content') { + currNode.removeAttribute(data.attrName); + } + } + }); + // using outerHTML as we want to preserve the html tag attributes (lang) return DOMPurify.sanitize(dom.outerHTML, { ADD_TAGS: tags, FORBID_TAGS: ['style'], + ADD_ATTR: ['http-equiv', 'content'], WHOLE_DOCUMENT: true, RETURN_DOM: true, }); diff --git a/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts b/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts index cc7ba6bace..c682008a4d 100644 --- a/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts +++ b/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts @@ -30,6 +30,8 @@ type TypographyHeadings = Pick< type TypographyHeadingsKeys = keyof TypographyHeadings; const headings: TypographyHeadingsKeys[] = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; +const relativeLengthUnit: RegExp = /(em)|(rem)/gi; +const cssVariable: RegExp = /var\(|\)/gi; export default ({ theme }: RuleOptions) => ` /*================== Typeset ==================*/ @@ -43,17 +45,27 @@ ${headings.reduce((style, heading) => { (theme.typography as BackstageTypography).htmlFontSize ?? 16; const styles = theme.typography[heading]; const { lineHeight, fontFamily, fontWeight, fontSize } = styles; - const calculate = (value: typeof fontSize) => { - let factor: number | string = 1; + const calculate = (value: typeof fontSize): string | undefined => { if (typeof value === 'number') { - // convert px to rem - // 60% of the size defined because it is too big - factor = (value / htmlFontSize) * 0.6; + // Convert px to rem and apply 60% factor + return calculate(`${(value / htmlFontSize) * 0.6}rem`); + } else if (typeof value === 'string') { + if (value.match(cssVariable)) { + // Resolve css variable and calculate recursively + const resolvedValue = window + .getComputedStyle(document.body) + .getPropertyValue(value.replaceAll(cssVariable, '')); + if (resolvedValue !== '') { + return calculate(resolvedValue); + } + } else if (value.match(relativeLengthUnit)) { + // Use relative size as factor + const factor = value.replace(relativeLengthUnit, ''); + return `calc(${factor} * var(--md-typeset-font-size))`; + } } - if (typeof value === 'string') { - factor = value.replace('rem', ''); - } - return `calc(${factor} * var(--md-typeset-font-size))`; + // Value is not a number, relative length unit, or CSS variable, return as is + return value; }; return style.concat(` .md-typeset ${heading} { diff --git a/plugins/techdocs/src/reader/transformers/styles/transformer.test.ts b/plugins/techdocs/src/reader/transformers/styles/transformer.test.ts deleted file mode 100644 index 90244e96ad..0000000000 --- a/plugins/techdocs/src/reader/transformers/styles/transformer.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { renderHook } from '@testing-library/react'; -import { useStylesTransformer } from './transformer'; - -describe('Transformers > Styles', () => { - it('should return a function that injects all styles into a given dom element', () => { - const { result } = renderHook(() => useStylesTransformer()); - - const dom = document.createElement('html'); - dom.innerHTML = ''; - result.current(dom); // calling styles transformer - - const style = dom.querySelector('head > style'); - expect(style).toHaveTextContent( - '/*================== Variables ==================*/', - ); - expect(style).toHaveTextContent( - '/*================== Reset ==================*/', - ); - expect(style).toHaveTextContent( - '/*================== Layout ==================*/', - ); - expect(style).toHaveTextContent( - '/*================== Typeset ==================*/', - ); - expect(style).toHaveTextContent( - '/*================== Animations ==================*/', - ); - expect(style).toHaveTextContent( - '/*================== Extensions ==================*/', - ); - }); -}); diff --git a/plugins/techdocs/src/reader/transformers/styles/transformer.test.tsx b/plugins/techdocs/src/reader/transformers/styles/transformer.test.tsx new file mode 100644 index 0000000000..b55e372212 --- /dev/null +++ b/plugins/techdocs/src/reader/transformers/styles/transformer.test.tsx @@ -0,0 +1,135 @@ +/* + * 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 { renderHook } from '@testing-library/react'; +import { useStylesTransformer } from './transformer'; +import { createTheme, ThemeProvider } from '@material-ui/core/styles'; +import React from 'react'; + +describe('Transformers > Styles', () => { + it('should return a function that injects all styles into a given dom element', () => { + const { result } = renderHook(() => useStylesTransformer()); + + const dom = document.createElement('html'); + dom.innerHTML = ''; + result.current(dom); // calling styles transformer + + const style = dom.querySelector('head > style'); + + expect(style).toHaveTextContent( + '/*================== Variables ==================*/', + ); + expect(style).toHaveTextContent( + '/*================== Reset ==================*/', + ); + expect(style).toHaveTextContent( + '/*================== Layout ==================*/', + ); + expect(style).toHaveTextContent( + '/*================== Typeset ==================*/', + ); + expect(style).toHaveTextContent( + '/*================== Animations ==================*/', + ); + expect(style).toHaveTextContent( + '/*================== Extensions ==================*/', + ); + }); + + it('should use headers relative font-size value as the factor for the md-typeset variable', () => { + const theme = createTheme({ + typography: { + h1: { + fontSize: '20rem', + }, + }, + }); + const wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} + ); + const { result } = renderHook(() => useStylesTransformer(), { wrapper }); + + const dom = document.createElement('html'); + dom.innerHTML = ``; + result.current(dom); // calling styles transformer + + const style = dom.querySelector('head > style'); + expect(style).not.toBeNull(); + + const h1 = style!.textContent?.match(/\.md-typeset h1 {.*?}/s); + expect(h1).toHaveLength(1); + expect(h1![0]).toContain( + 'font-size: calc(20 * var(--md-typeset-font-size));', + ); + }); + + it('should resolve header sizes that are variables', () => { + document.body.style.setProperty('--font-size-h1', '20rem'); + const theme = createTheme({ + typography: { + h1: { + fontSize: 'var(--font-size-h1)', + }, + }, + }); + const wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} + ); + const { result } = renderHook(() => useStylesTransformer(), { wrapper }); + + const dom = document.createElement('html'); + dom.innerHTML = ``; + result.current(dom); // calling styles transformer + + const style = dom.querySelector('head > style'); + expect(style).not.toBeNull(); + + const h1 = style!.textContent?.match(/\.md-typeset h1 {.*?}/s); + expect(h1).toHaveLength(1); + expect(h1![0]).toContain( + 'font-size: calc(20 * var(--md-typeset-font-size));', + ); + }); + + it('should convert pixel header sizes to REM and reduce by 60%', () => { + const theme = createTheme({ + typography: { + htmlFontSize: 16, + h1: { + fontSize: 100, + }, + }, + }); + const wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} + ); + const { result } = renderHook(() => useStylesTransformer(), { wrapper }); + + const dom = document.createElement('html'); + dom.innerHTML = ``; + result.current(dom); // calling styles transformer + + const style = dom.querySelector('head > style'); + expect(style).not.toBeNull(); + + const h1 = style!.textContent?.match(/\.md-typeset h1 {.*?}/s); + expect(h1).toHaveLength(1); + expect(h1![0]).toContain( + // 100px / 16px * 0.6 = 3.75rem + 'font-size: calc(3.75 * var(--md-typeset-font-size));', + ); + }); +}); diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index c830df43e5..144d27d627 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/plugin-user-settings-backend +## 0.2.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.8.0-next.2 + - @backstage/backend-common@0.23.4-next.2 + - @backstage/plugin-auth-node@0.5.0-next.2 + - @backstage/plugin-signals-node@0.1.9-next.2 + - @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.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.1 + - @backstage/backend-common@0.23.4-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.1 + - @backstage/plugin-signals-node@0.1.9-next.1 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.2.21-next.1 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index e975b38c08..808f59fec4 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings-backend", - "version": "0.2.21-next.1", + "version": "0.2.22-next.2", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 8d886aee80..a1aaa74828 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,74 @@ # @backstage/plugin-user-settings +## 0.8.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.7.0-next.2 + - @backstage/core-compat-api@0.2.8-next.2 + - @backstage/plugin-catalog-react@1.12.3-next.2 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.8.11-next.1 + +### Patch Changes + +- 6349099: Added config input type to the extensions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.1 + - @backstage/frontend-plugin-api@0.6.8-next.1 + - @backstage/core-compat-api@0.2.8-next.1 + - @backstage/core-app-api@1.14.2-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.8.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.8.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.8.9-next.2 ### Patch Changes diff --git a/plugins/user-settings/api-report-alpha.md b/plugins/user-settings/api-report-alpha.md index b06fd1e583..fdb2c5f6bf 100644 --- a/plugins/user-settings/api-report-alpha.md +++ b/plugins/user-settings/api-report-alpha.md @@ -18,9 +18,14 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const settingsNavItem: ExtensionDefinition<{ - title: string; -}>; +export const settingsNavItem: ExtensionDefinition< + { + title: string; + }, + { + title?: string | undefined; + } +>; // @alpha (undocumented) export const userSettingsTranslationRef: TranslationRef< diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 34c719d9df..4217cf3329 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.8.9-next.2", + "version": "0.8.11-next.2", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts b/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts index a421c413dc..6bb0035b83 100644 --- a/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts +++ b/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts @@ -21,14 +21,14 @@ import { IdentityApi, StorageApi, } from '@backstage/core-plugin-api'; -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { UserSettingsStorage } from './UserSettingsStorage'; describe('Persistent Storage API', () => { const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); const mockBaseUrl = 'http://backstage:9191/api'; const mockErrorApi = { post: jest.fn(), error$: jest.fn() }; diff --git a/storybook/.storybook/main.js b/storybook/.storybook/main.js index cb5f364a32..799c6c7c85 100644 --- a/storybook/.storybook/main.js +++ b/storybook/.storybook/main.js @@ -69,7 +69,7 @@ module.exports = Object.assign(({ args }) => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'ES2022', parser: { syntax: 'typescript', tsx: true, @@ -89,7 +89,7 @@ module.exports = Object.assign(({ args }) => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'ES2022', parser: { syntax: 'ecmascript', jsx: true, diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 1702d6f4cc..28bbe4b144 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -11912,17 +11912,17 @@ __metadata: linkType: hard "ws@npm:^8.2.3": - version: 8.8.1 - resolution: "ws@npm:8.8.1" + version: 8.18.0 + resolution: "ws@npm:8.18.0" peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: ">=5.0.2" peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - checksum: 2152cf862cae0693f3775bc688a6afb2e989d19d626d215e70f5fcd8eb55b1c3b0d3a6a4052905ec320e2d7734e20aeedbf9744496d62f15a26ad79cf4cf7dae + checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index b0bff82017..c14251269c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -489,674 +489,677 @@ __metadata: linkType: hard "@aws-sdk/client-codecommit@npm:^3.350.0": - version: 3.600.0 - resolution: "@aws-sdk/client-codecommit@npm:3.600.0" + version: 3.621.0 + resolution: "@aws-sdk/client-codecommit@npm:3.621.0" dependencies: "@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 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: 1a8197ffcf74b27a4b6159d8b4923db0f5c27b3d5daacb321ef956c49b0250800ce904c1c03264c67366c14244a8ba7a067849700b382979da19f7bc4c20a3fd + checksum: be8a5ebbe178f7d81c44a34f7e1ee54b8f7d3912c92de570855be4612cf60a02444957373eb9d9abfbf606f9998fc34acf020a2fb1d7be1e0e77be6c30388408 languageName: node linkType: hard -"@aws-sdk/client-cognito-identity@npm:3.600.0": - version: 3.600.0 - resolution: "@aws-sdk/client-cognito-identity@npm:3.600.0" +"@aws-sdk/client-cognito-identity@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/client-cognito-identity@npm:3.621.0" dependencies: "@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 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: ad01c387061da6d46767e209f3d422281e6af97d60ed61af687980990c7600ecbd88e2f430d975f029648d4475bf84234f710f4099edd2d61f90fef3444ee4a0 + checksum: 227fb03620396c3d5f9ca36fd463fc2e3e2e04909f5dea59b90e25a89d110d3a869e89e870237b808b494156bba06fb966406d2dc192a8ad6a072b7abdd4d81c languageName: node linkType: hard "@aws-sdk/client-eks@npm:^3.350.0": - version: 3.605.0 - resolution: "@aws-sdk/client-eks@npm:3.605.0" + version: 3.621.0 + resolution: "@aws-sdk/client-eks@npm:3.621.0" dependencies: "@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 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 - "@smithy/util-waiter": ^3.0.1 + "@smithy/util-waiter": ^3.1.2 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: 6cd87756d631fd18b12d21a89a938612ba17446cdc1de06c3c3a0ee488ffd8c9de4af3d27567524eb0e17155d423394e374002cb5a45d4376df6d82255abe870 + checksum: a69d67d1d6c447e541baebc06f2e5e4ac6532933422a0af2850c916075986c555d1e3ba9f397c1c35e95efd770642b5985d6f2c73d38cd566c4425fecc0dc2fa languageName: node linkType: hard "@aws-sdk/client-organizations@npm:^3.350.0": - version: 3.600.0 - resolution: "@aws-sdk/client-organizations@npm:3.600.0" + version: 3.621.0 + resolution: "@aws-sdk/client-organizations@npm:3.621.0" dependencies: "@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 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: b403a51e298fec8ec93553ac8a22a452408b0634b3a01d6c61ce271d7af69b1cef8907a9dce31fad79fa2cfc01fd6912d848e9b656b7a16f973e986b00bd727c + checksum: 28db7d0490cc93a512cc2299afa67ce01d60f2f07ec4a59f9e826c86ef0769164ac103128c0c8617ea86f0a4d2a7be2468803aace84e054e1db7a00c871f7783 languageName: node linkType: hard "@aws-sdk/client-s3@npm:^3.350.0": - version: 3.600.0 - resolution: "@aws-sdk/client-s3@npm:3.600.0" + version: 3.621.0 + resolution: "@aws-sdk/client-s3@npm:3.621.0" dependencies: "@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 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-bucket-endpoint": 3.620.0 + "@aws-sdk/middleware-expect-continue": 3.620.0 + "@aws-sdk/middleware-flexible-checksums": 3.620.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-location-constraint": 3.609.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-sdk-s3": 3.621.0 + "@aws-sdk/middleware-signing": 3.620.0 + "@aws-sdk/middleware-ssec": 3.609.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/signature-v4-multi-region": 3.621.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@aws-sdk/xml-builder": 3.609.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/eventstream-serde-browser": ^3.0.5 + "@smithy/eventstream-serde-config-resolver": ^3.0.3 + "@smithy/eventstream-serde-node": ^3.0.4 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-blob-browser": ^3.1.2 + "@smithy/hash-node": ^3.0.3 + "@smithy/hash-stream-node": ^3.1.2 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/md5-js": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-stream": ^3.1.3 "@smithy/util-utf8": ^3.0.0 - "@smithy/util-waiter": ^3.0.1 + "@smithy/util-waiter": ^3.1.2 tslib: ^2.6.2 - checksum: be9940ac1a9bff2e8efbf6f0ac782b0bcd66ab229639dc46d60aa71e041b3ef16a327e37c92397691a16c982cf5e529ab2ffd60351a9d9730bf4947bb391ced4 + checksum: 120bfaa142a61a8dbc2f82d6fe5e36cb2ec0acdb12390795d15326dfad4f67b0d2e95515afb04da34b3f686fef0368f7a79a20c85735b28df654cbc5bdb1f04c languageName: node linkType: hard "@aws-sdk/client-ses@npm:^3.550.0": - version: 3.600.0 - resolution: "@aws-sdk/client-ses@npm:3.600.0" + version: 3.621.0 + resolution: "@aws-sdk/client-ses@npm:3.621.0" dependencies: "@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 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 - "@smithy/util-waiter": ^3.0.1 + "@smithy/util-waiter": ^3.1.2 tslib: ^2.6.2 - checksum: f0c042db4e20b8165f7da42ba2026ee6c32944c10c6a3508c021efbc0a3474fd0ef888367db47f54dc89a6bbad482858b0c816f6d3ec4ac84bfc156d315b2381 + checksum: 40de6b66fc6ac93eae26906cfb77b9a9d4bfd1a990e68f5bdc1a7024a624397e470149c1054e904c181b87b09e1a9d1ec4308dc206ffdfa5740113c0a199b5eb languageName: node linkType: hard "@aws-sdk/client-sqs@npm:^3.350.0": - version: 3.600.0 - resolution: "@aws-sdk/client-sqs@npm:3.600.0" + version: 3.621.0 + resolution: "@aws-sdk/client-sqs@npm:3.621.0" dependencies: "@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 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-sdk-sqs": 3.621.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/md5-js": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: e0ec11d0d89539ae1964cc2f0655af7367c0c43153ab16fe9542e303cd1b69c5f0e9f3d912c52ff7bbfc5f557733d52e187e72563f0bfed3a21ed6249ae37c8a + checksum: 293d3164570623e6228fc9e14c803b20e7ca5e562ce470f6f8ee3adf2b9a4cffd886ab69859d60afa1cf46f2df8cd9e0190a081335c1c2be21fee0739f21ce9f languageName: node linkType: hard -"@aws-sdk/client-sso-oidc@npm:3.600.0": - version: 3.600.0 - resolution: "@aws-sdk/client-sso-oidc@npm:3.600.0" +"@aws-sdk/client-sso-oidc@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/client-sso-oidc@npm:3.621.0" dependencies: "@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 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@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-defaults-mode-browser": ^3.0.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: ef7a40ce69de30b25a8a7a5ee035f17e87edc1060c128b3b50f30f19b681aaa7b99b564ffc348cd74fe0e1079bd46087a6784674266d743c45564bcd4d5221b3 - languageName: node - linkType: hard - -"@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": 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: b570f54643ac0ab0f300bf074e77c2fbba70206a11d2aed1f6ecd361027f2f6a1d62719627e905bcb44dd73d481a29ef5a70878c676386afe2a133f479a445d4 - languageName: node - linkType: hard - -"@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": 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 - checksum: 47d6d145d481c8dc285b68baccf36ab76b92ed1fbf5a58a0900bbe913a7caf3eddc84414428b013e58c91242e7ffd5a55b0620217dc295c75c2729ccb89b9ae8 - languageName: node - linkType: hard - -"@aws-sdk/core@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/core@npm:3.598.0" - dependencies: - "@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: e58944a6571808b53d21f012b9671ffec597d2a826a9c0f1fbcbe160189a3c47f5b4671ac92b7437c349f19b8a8df7e12255c57795ab0224c318ed69a0d23229 - languageName: node - linkType: hard - -"@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.600.0 - "@aws-sdk/types": 3.598.0 - "@smithy/property-provider": ^3.1.1 - "@smithy/types": ^3.1.0 - tslib: ^2.6.2 - checksum: 9e7e325fde26192fbd7f542ad0ff69d193b5edb65b0361cdeb13f538b1b563de999e82da34493921351ea599643c4884bd17fdc16eba423d3343e681f346072f - languageName: node - linkType: hard - -"@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.598.0 - "@smithy/property-provider": ^3.1.1 - "@smithy/types": ^3.1.0 - tslib: ^2.6.2 - checksum: 517f06dd47b7aa4c8d5a9fe82698150237c28c46ed9f82cd1d92d1453690b9d6139b65519d92dea611d319c4418fe4540e7d52c03d3897e7e471731fb0156afb - languageName: node - linkType: hard - -"@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.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: e2f6208491a6e58b7ac7368c2247dee55080be740511ded01cc3454920ef29d0b7712930571651a8d0ec2aea4e0a107c7d5dd6ecd01bd4de3c264c54e32959b3 - languageName: node - linkType: hard - -"@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/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 peerDependencies: - "@aws-sdk/client-sts": ^3.598.0 - checksum: 9fab1e9c312e20150c96daf15e0347b79f0589cc44eb299c15e80c7d5380e8966805fa8893d3c906f99b7eb3c0f872f0795415f75921204580a30d869dd87f54 + "@aws-sdk/client-sts": ^3.621.0 + checksum: 12aa50a56f2498a9202b877b0b789fa95c038707b648dc3c9e93976c209ed3d4518868279707ee8fe12f42858eba7181098bdbf68556341c9017bd5e31f89135 languageName: node linkType: hard -"@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" +"@aws-sdk/client-sso@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/client-sso@npm:3.621.0" dependencies: - "@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 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@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.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 480c7c36a8558667a25617e6f7f2292b4362b0e894bc204ce62f565dc8e8cc46c713dc04621321336ce715b493590b3b854b33dc6d5123ed39a17643158d94fc + checksum: fe72875685c07b9cf42b7fcde06502d42a5398161b37de87c5360f10a0d28cf7b32fc95f5eecdf782cff04c8109bd7a20d9644bfacc78e3521b6a7670ed76b40 languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.598.0" +"@aws-sdk/client-sts@npm:3.621.0, @aws-sdk/client-sts@npm:^3.350.0": + version: 3.621.0 + resolution: "@aws-sdk/client-sts@npm:3.621.0" dependencies: - "@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 + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.621.0 + "@aws-sdk/core": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.1 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@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.13 + "@smithy/util-defaults-mode-node": ^3.0.13 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: cd1f0dbbc38b137a0e9c2cfa9bb9e55eed1da5166e13576295205d276ab313e9d4a2f97a566d576abc85c6f4e9e84ad676ca5c32f90de17e027d6a1372fb00e6 + checksum: 35f543e1c4b419dc598489b4ce4dfbce22ad726ffe8f807876de13c0e8b5db10684835f7b95841e988d4f16aeb921935133e5775d35b47186c18cced6715a82a languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.598.0" +"@aws-sdk/core@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/core@npm:3.621.0" dependencies: - "@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 + "@smithy/core": ^2.3.1 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/signature-v4": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/util-middleware": ^3.0.3 + fast-xml-parser: 4.4.1 tslib: ^2.6.2 - checksum: 16828609b9ac17772eecd89deb9ac9b98a1decad42ca1f8cf6a57e6873eeb3563db00bfb67684cbb08108d5ee6b8f98ec23047d7f6750cb67c1342cd8b96ac1c + checksum: 789409227f2aa0f3c735e0f1bebf1d900b359e589bad50324e2fbec20ddb30435e1dcf9132501dad7aaf793829530980d1670257208c5e407c78be5f831e796d languageName: node linkType: hard -"@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" +"@aws-sdk/credential-provider-cognito-identity@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.621.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/property-provider": ^3.1.1 - "@smithy/types": ^3.1.0 + "@aws-sdk/client-cognito-identity": 3.621.0 + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: e8a913d61ac4e772e07cd1a6144ef8680e630894c2192aed81d06f36fb9607c4de3b95386155d52f050b99d8b4d78ceb69eb7fa0987d339631765cc1dc8c9588 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-env@npm:3.620.1": + version: 3.620.1 + resolution: "@aws-sdk/credential-provider-env@npm:3.620.1" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 3e05eeb6c6490e7759d03b7b688ef321d5e6c97929f21226e912b01aa926815312043febd505e8b43b54010b5ae2717559aba6deeea93bda7d6cf0d8a0b9fc76 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-http@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/credential-provider-http@npm:3.621.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/property-provider": ^3.1.3 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/util-stream": ^3.1.3 + tslib: ^2.6.2 + checksum: bc45dfe7d0a6868978d71fa73731784af1839f822c09ef13b5a08ad74fa57c008dd874dd1765317df61ab022f9470bf509df38a70dd0aa5262d1d2234cc5eda2 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-ini@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.621.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.620.1 + "@aws-sdk/credential-provider-http": 3.621.0 + "@aws-sdk/credential-provider-process": 3.620.1 + "@aws-sdk/credential-provider-sso": 3.621.0 + "@aws-sdk/credential-provider-web-identity": 3.621.0 + "@aws-sdk/types": 3.609.0 + "@smithy/credential-provider-imds": ^3.2.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 peerDependencies: - "@aws-sdk/client-sts": ^3.598.0 - checksum: e62352ae7f408ae8969d22fd42a502ec078536952be1253f184bf96c57f3c88589fd431762b2300b494159df4eb4af975358645772ac36f2cc722c86a88ff85e + "@aws-sdk/client-sts": ^3.621.0 + checksum: a3db43adfbdb2ea1d6d80b1ca6789e48b729fce2499039f99721f504322cba325e4b48ed842bd26ae6f49ca771e5817016b75cda31cf247fd3e2bd0ac235b332 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-node@npm:3.621.0, @aws-sdk/credential-provider-node@npm:^3.350.0": + version: 3.621.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.621.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.620.1 + "@aws-sdk/credential-provider-http": 3.621.0 + "@aws-sdk/credential-provider-ini": 3.621.0 + "@aws-sdk/credential-provider-process": 3.620.1 + "@aws-sdk/credential-provider-sso": 3.621.0 + "@aws-sdk/credential-provider-web-identity": 3.621.0 + "@aws-sdk/types": 3.609.0 + "@smithy/credential-provider-imds": ^3.2.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: aada1f0624caee0e00b9ba287e66120031c8f5095acbcd80723b2ab6b5e4bffcd662665fffe62b7f2091bfb89d33ea13212a82893318005699914f13fbed70c3 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-process@npm:3.620.1": + version: 3.620.1 + resolution: "@aws-sdk/credential-provider-process@npm:3.620.1" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 1fd6d3abf35ccfaed0882ee74e4d876e8c6cfe8d8b23c574dfe98364b2a2f3226d97fe35e2d48b88dd514906595cbb5fa1e0066d989a9582f73f92117796168f + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-sso@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.621.0" + dependencies: + "@aws-sdk/client-sso": 3.621.0 + "@aws-sdk/token-providers": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 4602308a0bf74bda9dd7b92caf02868b855935deb703a8894d052c81864ef9c9359408ec84569f71527c1b204577940ebe1a9f6cbba8de677471eb590d91c3ba + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-web-identity@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.621.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + peerDependencies: + "@aws-sdk/client-sts": ^3.621.0 + checksum: b1157e83b81c21f384ad95d29c646149124136c38e6395265ff8d9f5f6afec1e3e2b70c1f0be165c440058802c3871f3766c5e7ba44705ced447de221f4d04df languageName: node linkType: hard "@aws-sdk/credential-providers@npm:^3.350.0": - version: 3.600.0 - resolution: "@aws-sdk/credential-providers@npm:3.600.0" + version: 3.621.0 + resolution: "@aws-sdk/credential-providers@npm:3.621.0" dependencies: - "@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 + "@aws-sdk/client-cognito-identity": 3.621.0 + "@aws-sdk/client-sso": 3.621.0 + "@aws-sdk/client-sts": 3.621.0 + "@aws-sdk/credential-provider-cognito-identity": 3.621.0 + "@aws-sdk/credential-provider-env": 3.620.1 + "@aws-sdk/credential-provider-http": 3.621.0 + "@aws-sdk/credential-provider-ini": 3.621.0 + "@aws-sdk/credential-provider-node": 3.621.0 + "@aws-sdk/credential-provider-process": 3.620.1 + "@aws-sdk/credential-provider-sso": 3.621.0 + "@aws-sdk/credential-provider-web-identity": 3.621.0 + "@aws-sdk/types": 3.609.0 + "@smithy/credential-provider-imds": ^3.2.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: d957d851a9d4aba30e941c12515ce08fda66cadf2623fa329a2f651e2229e901a7845b139cd15404c8a714985e9b358747f1a8aacf0951e9b05331c5ae92af7c + checksum: 152a8911ca52a0663e4552e720f73bef2d93088d7b9fc58da88cf2aac91ebc3b720ea8abc5d28228d1658888903bd737dbba88e7d5cc97e2a2c7fdc0e5243c6f languageName: node linkType: hard @@ -1182,34 +1185,34 @@ __metadata: linkType: hard "@aws-sdk/lib-storage@npm:^3.350.0": - version: 3.600.0 - resolution: "@aws-sdk/lib-storage@npm:3.600.0" + version: 3.621.0 + resolution: "@aws-sdk/lib-storage@npm:3.621.0" dependencies: - "@smithy/abort-controller": ^3.0.1 - "@smithy/middleware-endpoint": ^3.0.2 - "@smithy/smithy-client": ^3.1.2 + "@smithy/abort-controller": ^3.1.1 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/smithy-client": ^3.1.11 buffer: 5.6.0 events: 3.3.0 stream-browserify: 3.0.0 tslib: ^2.6.2 peerDependencies: - "@aws-sdk/client-s3": ^3.600.0 - checksum: 3fc04712f61289ac47f9502f0f33351a50e581d7999398575e84713750c77261b20ef8ac4f0a68514737c9950b313a563752b6856f63acaff23d128a4b4a9f4b + "@aws-sdk/client-s3": ^3.621.0 + checksum: 6c84a1601bcbea53aabad52c2453afd3c577e3935eda4bb13a7d9d4b1405289a3f2f4747327fc30c5eeaf482a9a78d56dfb4453c4c892f876f491e677d0f6c95 languageName: node linkType: hard -"@aws-sdk/middleware-bucket-endpoint@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.598.0" +"@aws-sdk/middleware-bucket-endpoint@npm:3.620.0": + version: 3.620.0 + resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.620.0" dependencies: - "@aws-sdk/types": 3.598.0 + "@aws-sdk/types": 3.609.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/node-config-provider": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 "@smithy/util-config-provider": ^3.0.0 tslib: ^2.6.2 - checksum: 45a4adc3427a70f7129675439c9396073dc418e9e5ede4acd0dc0620d76610e8adf3f1c863120f7714bc67053a194289ac55ce6814a79960c4746cbd45f7116f + checksum: a5539ad611d3a2f7709952bf735a075a9d18ed5e9c0abe4e268bca32775a2100f3e956a264f6afb0ad0b48600f5b1d3389ec0566cd2795e6ae2dbe5af322b56b languageName: node linkType: hard @@ -1226,108 +1229,110 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-expect-continue@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-expect-continue@npm:3.598.0" +"@aws-sdk/middleware-expect-continue@npm:3.620.0": + version: 3.620.0 + resolution: "@aws-sdk/middleware-expect-continue@npm:3.620.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/protocol-http": ^4.0.1 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 1038945711d48d661cbf21343fd78968240f43b18f5b7fade7e41a7bf5308a65f37859f2b349e5fb038dded0136e0ea734e38e52085178b6a546a6ac48c630e9 + checksum: 739af454854562342984ac5e3c1c3dca39205344f52eda5961dae80020595062eaae6da2f76bf48ad486d92041c2a2bd30f1dd67b8b20ae043897d1d27b1a6bb languageName: node linkType: hard -"@aws-sdk/middleware-flexible-checksums@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.598.0" +"@aws-sdk/middleware-flexible-checksums@npm:3.620.0": + version: 3.620.0 + resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.620.0" dependencies: "@aws-crypto/crc32": 5.2.0 "@aws-crypto/crc32c": 5.2.0 - "@aws-sdk/types": 3.598.0 + "@aws-sdk/types": 3.609.0 "@smithy/is-array-buffer": ^3.0.0 - "@smithy/protocol-http": ^4.0.1 - "@smithy/types": ^3.1.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 1311849976b0631055d2d79f991647a87cae742bba23a94f01d18164612ba303ff3bed629744ba58c04bfde371b69ad4eb29e266a7b022ea8529b9a7f6a18415 + checksum: 2fc70ffa826d94924c0dae92ed5250c85aade93cbc15a488df81683d8f32eb7660f546569b1c2d2e878db5c8da02a83a3a98c331c5bb3adca46362e667abcbed languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.598.0" +"@aws-sdk/middleware-host-header@npm:3.620.0": + version: 3.620.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.620.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/protocol-http": ^4.0.1 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: c505de5bf4f39051a55011b9b2da0b673bda668def00a9b3b4696a3146bfbf0e5509d3bde28ef238648158b863816ce85fbf5829228bb97450c826b7d24d40d0 + checksum: 829c2d230e5051704f45c5283c42bec657607f4e4b2dd251fda8a716be90f8c9dfd6e7d45892a9a558c35cb64711628b3d0f88b90fe8cd061382c70b473991ef languageName: node linkType: hard -"@aws-sdk/middleware-location-constraint@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-location-constraint@npm:3.598.0" +"@aws-sdk/middleware-location-constraint@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/middleware-location-constraint@npm:3.609.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: ab1ae3ad3dc7fad76688c039136d602abe25ebd6b98b6fb61a86f02dbec4414a74334169d12581aae720fe9d372549e9b9dfb56ee87388602264b697db09ff9f + checksum: f7962cf0b382efdf56cd07f8c0279efead02365edd7a2c124be39551b51a8359ee0d6f0399fcbf679ead3d235e24d1765f79712cf88e06c0a5432bf2d0c317d8 languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-logger@npm:3.598.0" +"@aws-sdk/middleware-logger@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/middleware-logger@npm:3.609.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 8c90bf68b65fe82ae08bf0c665bfea335fef757f8be7ddac6f9059f9f149c9bebc68e034bc225d131d168a61d61a409936d4f4d260c4b2aa2251385238df765a + checksum: b6f67a2e9ba082c8aec9d45905ae45ea5a95896f1beecb0c2d7fecfe17dd8fad99513f43b11ed7fd6ca9ff7764a0fc1ce63af91b1baed92b36f7b4b5390be5c6 languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.598.0" +"@aws-sdk/middleware-recursion-detection@npm:3.620.0": + version: 3.620.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.620.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/protocol-http": ^4.0.1 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 161247dbbc8aa31d77c8d4c9c55264c775b5f9996e58451574605435c4a0ff6b9fce28be6f133ddce9f93a24f08c7af6fde59ef93ecb2cc4cd170a4db72b4833 + checksum: 1dedbbab2f79d4c0b214ca183a45daf89e98f9a33b2a08dcd7d30e059c1bcc04a74499b49870300d5f0b827d660512582f96f857624d3feaaf194a7a92703cea languageName: node linkType: hard -"@aws-sdk/middleware-sdk-s3@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-sdk-s3@npm:3.598.0" +"@aws-sdk/middleware-sdk-s3@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/middleware-sdk-s3@npm:3.621.0" dependencies: - "@aws-sdk/types": 3.598.0 + "@aws-sdk/types": 3.609.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/node-config-provider": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/signature-v4": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 "@smithy/util-config-provider": ^3.0.0 + "@smithy/util-stream": ^3.1.3 + "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 2953ae0f2729ffc4ca68e51e8f3247d447004e5d3d787b333351f2972cc94b49f8379f3403d153c3c5940bda47e1930b0386b77c448ca81bc54bf40f7cb4111f + checksum: 2db38ad1575e9209f053474ff69731d0c0910304fc14dcdf22a09c06a849cbada0b18f36879d96e3020c0e050f80b02e47c45137da561a3f243cc080f6df4f3a languageName: node linkType: hard -"@aws-sdk/middleware-sdk-sqs@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.598.0" +"@aws-sdk/middleware-sdk-sqs@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.621.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/smithy-client": ^3.1.2 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 "@smithy/util-hex-encoding": ^3.0.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 5b31bc50ffb2973a1a5108ca0a9a2fbf3cc96a403fd06e58994eb9e98e5804cb8fd2d2db977214d92ce30a5a256b54df156b285f7a89e286e7d0ceb3d9f69414 + checksum: d0cad52b1ffbfc6078fd62865bb88b4ac3b3a06d883ad5ef0a419dfaefe11d33314892f862150801d57e8c277e3a1465f8e798a1176c1ad6090765faf325c1d0 languageName: node linkType: hard @@ -1341,42 +1346,42 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-signing@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-signing@npm:3.598.0" +"@aws-sdk/middleware-signing@npm:3.620.0": + version: 3.620.0 + resolution: "@aws-sdk/middleware-signing@npm:3.620.0" dependencies: - "@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 + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/protocol-http": ^4.1.0 + "@smithy/signature-v4": ^4.1.0 + "@smithy/types": ^3.3.0 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: c952da22635dbca7b91c47e43df43a9f4826bbebc36e5851ce325e07f43451de015232145df32eed3190b23d3b051469bf4c381b94ab4eb367ca8f22de4a4670 + checksum: ef2365b282ccfe8dc29983b620ca6cd5f2e41f5f8d12b84d2e3cb73866535ba3f7383579e561ec5a3c422d3fefdfbb2f3461ae7806a9f87e4fe92fd10a929386 languageName: node linkType: hard -"@aws-sdk/middleware-ssec@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-ssec@npm:3.598.0" +"@aws-sdk/middleware-ssec@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/middleware-ssec@npm:3.609.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 600afb96254d1085c402fec6c5b7f260ca64126104c4cf3ff6da9811c5cdf0dab5f34fadf68e449ec61f89a165479e1cfab8cd3135c720a2e7a678be4572c215 + checksum: 4b40627ed103159ef0db4cc6bdc2148d1a65b786f3d1c643d34bccc79b9d265495613dc9bb34d18d5ab9b21b5d31110e495ec2b077e6e2f7603a0493254180a2 languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.598.0" +"@aws-sdk/middleware-user-agent@npm:3.620.0": + version: 3.620.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.620.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@aws-sdk/util-endpoints": 3.598.0 - "@smithy/protocol-http": ^4.0.1 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 11dcf64badadf8c6b3283b3cec4cb684467eaf57206782c68a9b758e6f7a4f1b632d5ed89bb6ffbc855bf6d3fb855f0a56858bda640a67c0812ced08cd19959f + checksum: 137a969b5c17ebf172aa1f5a393812c443425dd9833fdf786a3039af5b3197e7d17139659891858b268ff723d9f2c5fbc840e8ac6a7af4b1cb566a3d54746a51 languageName: node linkType: hard @@ -1424,31 +1429,31 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.598.0" +"@aws-sdk/region-config-resolver@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.614.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/node-config-provider": ^3.1.1 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 "@smithy/util-config-provider": ^3.0.0 - "@smithy/util-middleware": ^3.0.1 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: 649115771cb6b77e793088f3ee6eec346c1379f9f5d0e925f71103ad55c5f4a1132fca7e859a6b75ff46ecd1cc165a4eb260227596e4a2871118e6918602a726 + checksum: dbaca50792c99685845b21dd4a53228613e0458ee517a21db941890ee521d91eff80704f08e9ee71b6f04e70fb86362c4823750bb0b3727240af68d78d8fa4be languageName: node linkType: hard -"@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" +"@aws-sdk/signature-v4-multi-region@npm:3.621.0": + version: 3.621.0 + resolution: "@aws-sdk/signature-v4-multi-region@npm:3.621.0" dependencies: - "@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 + "@aws-sdk/middleware-sdk-s3": 3.621.0 + "@aws-sdk/types": 3.609.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/signature-v4": ^4.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 6e0aa7adfe98c452eaa269ea9dc68d2b914a3c5bdc00b5923c0a9003e54899b7d3b9ce14d305b5229200e658a18fdebb93977437f029e9a576c9fe9a3cded0b1 + checksum: 741c07e65341da4c807d55b0bc6f1ec0064190c6fceb7571b0796f6ec94cc156a6214c0f308a93ad364884adae48502d248d30bd0ef43e7a4542586f264982c4 languageName: node linkType: hard @@ -1468,18 +1473,18 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/token-providers@npm:3.598.0" +"@aws-sdk/token-providers@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/token-providers@npm:3.614.0" dependencies: - "@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 + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 peerDependencies: - "@aws-sdk/client-sso-oidc": ^3.598.0 - checksum: 24197672226e1e953fa57ca10c6adae9c3f6b571fbf40f517609e028d8ea6ab45c3afd285bd999bc35c0690b3427be04d4af3f677ced6778b0a716e0dd4e5280 + "@aws-sdk/client-sso-oidc": ^3.614.0 + checksum: 2901b8428afc3b76ff1df9ac29a2698db6bf65d1d2afcd8424b9bf187313d2a3ca747c3b205afeb5c132068b5a5a94d84ce82710f775fa0cbb79499d7fea2d64 languageName: node linkType: hard @@ -1493,13 +1498,13 @@ __metadata: languageName: node linkType: hard -"@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" +"@aws-sdk/types@npm:3.609.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.347.0": + version: 3.609.0 + resolution: "@aws-sdk/types@npm:3.609.0" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 9b2bd50d6935422dd1046e6eaa48c4c774d06aa1374bf4600a3af2c7a52432b5e25ec111cf49976b07b03d7cb5f4fa6fd44b7ce8a67dd0b3a4cee4abaf9e6fa5 + checksum: 522768d08f104065b0ff6a37eddaa7803186014acee1c0011b3dbd3ef841e47ae694e58f608aeec8a39d22d644d759ade996fe51d18b880617778dc2dbbe1ede languageName: node linkType: hard @@ -1533,15 +1538,15 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/util-endpoints@npm:3.598.0" +"@aws-sdk/util-endpoints@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/util-endpoints@npm:3.614.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/types": ^3.1.0 - "@smithy/util-endpoints": ^2.0.2 + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 + "@smithy/util-endpoints": ^2.0.5 tslib: ^2.6.2 - checksum: 6fb92e8c99b6ce96cda21c9d1744a290c683bae8d82394c1b1fe7ed7d3cb0a18d4025b8863532680db3f550ad130e54d528c64a0a32f398f3c00c5ce2e043ecd + checksum: 9d9973ceee59bf30af85c7f4328083daea033a987ec396dcb89eb7649f470ceb19c6b96635e121f3557e726f7ec7453236c956cf43f22128883c277f17d2a13f languageName: node linkType: hard @@ -1593,32 +1598,32 @@ __metadata: languageName: node linkType: hard -"@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" +"@aws-sdk/util-user-agent-browser@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.609.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 bowser: ^2.11.0 tslib: ^2.6.2 - checksum: c53afc0fe7a07838ad22ae1e9ed6834d56a69cb0ad623d4912deeaa715af479b64266965fce30e7210e576118f80ceb525f79f504dc459fe0294fd15e694752e + checksum: 75ba1ae74dd1001f47870766d92b66ac02a0a488efcf42c1a368962a7978a778d99536e880f07f7db1c2ca66cc9b1863fd3342957a22dcf78bf2f4398265a7a5 languageName: node linkType: hard -"@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" +"@aws-sdk/util-user-agent-node@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.614.0" dependencies: - "@aws-sdk/types": 3.598.0 - "@smithy/node-config-provider": ^3.1.1 - "@smithy/types": ^3.1.0 + "@aws-sdk/types": 3.609.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 peerDependencies: aws-crt: ">=1.0.0" peerDependenciesMeta: aws-crt: optional: true - checksum: 1560fabf19b236cfbce42769e1ef7e46bdad881b8a4b0ce069401d9a6edd5e1b195f45cb2847abf9ef1453d2e69447e7a3dabc92b037d9a41fe58960538db1ae + checksum: 1f010080c2301fd836908963a235ef39e597d959e27461d15d4958fa582ab20795022f8cb7429c183c386f558a5c125cb254a0c4e844dbc6422169f4884be34a languageName: node linkType: hard @@ -1641,13 +1646,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/xml-builder@npm:3.598.0": - version: 3.598.0 - resolution: "@aws-sdk/xml-builder@npm:3.598.0" +"@aws-sdk/xml-builder@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/xml-builder@npm:3.609.0" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 6b9fa385f749219d0a0654445e5deba54c7753d3e0da795dfc2bfdbaeb59fbfc8ef0e3f477c6aff6181a12a11ac87e3f84dedbbd1d1adb2c32941b149401abcf + checksum: 0e9c8b7786737ff50a6cf39f7ca9a758897c2db364718364b5dad45f50a33e65bd7801348fd033af60768a5be64b454c3a7e65222e13c70d145e8df6211ca33c languageName: node linkType: hard @@ -3384,22 +3389,22 @@ __metadata: languageName: node linkType: hard -"@backstage-community/plugin-explore-common@npm:^0.0.3": - version: 0.0.3 - resolution: "@backstage-community/plugin-explore-common@npm:0.0.3" - checksum: 54b81496122c11bd16cbb71c4fcc92e6bf16b5e4f580fc8043dbea35955447d67b463a40065e629ed81ef3aeeb36d1f41d445b7fa4d8ab7e0036a296b361e398 +"@backstage-community/plugin-explore-common@npm:^0.0.4": + version: 0.0.4 + resolution: "@backstage-community/plugin-explore-common@npm:0.0.4" + checksum: 0c27253dd79dcb56236d382f7591e20eb87f374878b091a690b3fede23ff652aefa3b074a58bd5b51462cc44faab12a97ee82443dcc6106f121212417b9c4cf9 languageName: node linkType: hard "@backstage-community/plugin-puppetdb@npm:^0.1.18": - version: 0.1.18 - resolution: "@backstage-community/plugin-puppetdb@npm:0.1.18" + version: 0.1.19 + resolution: "@backstage-community/plugin-puppetdb@npm:0.1.19" dependencies: - "@backstage/catalog-model": ^1.4.5 - "@backstage/core-components": ^0.14.4 - "@backstage/core-plugin-api": ^1.9.2 + "@backstage/catalog-model": ^1.5.0 + "@backstage/core-components": ^0.14.9 + "@backstage/core-plugin-api": ^1.9.3 "@backstage/errors": ^1.2.4 - "@backstage/plugin-catalog-react": ^1.11.3 + "@backstage/plugin-catalog-react": ^1.12.2 "@material-ui/core": ^4.12.2 "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 react-use: ^17.2.4 @@ -3407,16 +3412,16 @@ __metadata: 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: d0e4fe3f818aa05c527d773d558291b97f3a4fee1b1a765e0e6f5a2f36ca1897e3933e92abdeffeb8b33701c21314eb3565900ff78624fe1d5eff3ee2781cfff + checksum: abe5e3b5b9772b5cdc17074f58f38bdbf81516afe7b9241e06844729608ec2a56899437a7cf82d4c8f3608038c15217bd6ea971f41dbce2934e7b05986bfcc10 languageName: node linkType: hard "@backstage-community/plugin-stackstorm@npm:^0.1.16": - version: 0.1.16 - resolution: "@backstage-community/plugin-stackstorm@npm:0.1.16" + version: 0.1.17 + resolution: "@backstage-community/plugin-stackstorm@npm:0.1.17" dependencies: - "@backstage/core-components": ^0.14.4 - "@backstage/core-plugin-api": ^1.9.2 + "@backstage/core-components": ^0.14.9 + "@backstage/core-plugin-api": ^1.9.3 "@backstage/errors": ^1.2.4 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 @@ -3426,7 +3431,7 @@ __metadata: 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: 2fd7d290cd98ad09b16862a5dee3302796942e85818abf9c4a9102038a4fb83e86ceee39d901e59bb7fb7c60df7797524f8c6a5cfee1a4a0ea59edcbb4de5a0a + checksum: 3fa2b45da036e4001a9e034a8841b58877d0b4189d244806b3b1808d3c2a34bb4ab4acbcff629edda47d03b2941c51743dd84f7352ed0d700988aaee946b65f3 languageName: node linkType: hard @@ -3498,7 +3503,7 @@ __metadata: minimist: ^1.2.5 morgan: ^1.10.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 node-forge: ^1.3.1 path-to-regexp: ^6.2.1 selfsigned: ^2.0.0 @@ -3583,7 +3588,7 @@ __metadata: morgan: ^1.10.0 msw: ^1.0.0 mysql2: ^3.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 node-forge: ^1.3.1 p-limit: ^3.1.0 path-to-regexp: ^6.2.1 @@ -3672,7 +3677,7 @@ __metadata: morgan: ^1.10.0 msw: ^1.0.0 mysql2: ^3.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 node-forge: ^1.3.1 p-limit: ^3.1.0 path-to-regexp: ^6.2.1 @@ -3852,7 +3857,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.4.3, @backstage/catalog-model@^1.4.5, @backstage/catalog-model@^1.5.0, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.4.3, @backstage/catalog-model@^1.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: @@ -3917,6 +3922,7 @@ __metadata: "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 + "@module-federation/enhanced": ^0.1.19 "@octokit/graphql": ^5.0.0 "@octokit/graphql-schema": ^13.7.0 "@octokit/oauth-app": ^4.2.0 @@ -4003,7 +4009,7 @@ __metadata: mini-css-extract-plugin: ^2.4.2 minimatch: ^9.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 node-libs-browser: ^2.2.1 nodemon: ^3.0.1 npm-packlist: ^5.0.0 @@ -4097,7 +4103,7 @@ __metadata: lodash: ^4.17.21 minimist: ^1.2.5 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 typescript-json-schema: ^0.63.0 yaml: ^2.0.0 zen-observable: ^0.10.0 @@ -4165,6 +4171,7 @@ __metadata: "@backstage/frontend-plugin-api": "workspace:^" "@backstage/frontend-test-utils": "workspace:^" "@backstage/plugin-catalog": "workspace:^" + "@backstage/test-utils": "workspace:^" "@backstage/version-bridge": "workspace:^" "@oriflame/backstage-plugin-score-card": ^0.8.0 "@testing-library/jest-dom": ^6.0.0 @@ -4227,9 +4234,9 @@ __metadata: 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" +"@backstage/core-components@npm:^0.14.9": + version: 0.14.9 + resolution: "@backstage/core-components@npm:0.14.9" dependencies: "@backstage/config": ^1.2.0 "@backstage/core-plugin-api": ^1.9.3 @@ -4272,7 +4279,7 @@ __metadata: 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 + checksum: cf89c9e19dd33270bdc2bb9e7d89487c71b78e6645dcef9a6ac0d1df67b52e4eee61f2873abe093ed921d756a75f97e870c294aa5c2a730598e520b06e38b41f languageName: node linkType: hard @@ -4347,7 +4354,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@^1.8.2, @backstage/core-plugin-api@^1.9.2, @backstage/core-plugin-api@^1.9.3, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.8.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: @@ -4389,7 +4396,7 @@ __metadata: handlebars: ^4.7.3 inquirer: ^8.2.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 nodemon: ^3.0.1 ora: ^5.3.0 recursive-readdir: ^2.2.2 @@ -4494,11 +4501,11 @@ __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" +"@backstage/frontend-plugin-api@npm:^0.6.7": + version: 0.6.7 + resolution: "@backstage/frontend-plugin-api@npm:0.6.7" dependencies: - "@backstage/core-components": ^0.14.8 + "@backstage/core-components": ^0.14.9 "@backstage/core-plugin-api": ^1.9.3 "@backstage/types": ^1.1.1 "@backstage/version-bridge": ^1.0.8 @@ -4510,7 +4517,7 @@ __metadata: peerDependencies: react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: c2af07bb73751f050937ba0f34941cc21639defdf13c6e219069ff4143324404229113874caef28f41b9a92a00121991da2a88782595e5221b48910e2f8be7c7 + checksum: cf7485aedcae02c5855a62adea6fffcfad256d614731ade38d2bebd5f98e91aa5d1020cd9ac25b74d67d2681c010addff4a89d5be1e2deb2e688bf1915134c32 languageName: node linkType: hard @@ -4545,6 +4552,7 @@ __metadata: resolution: "@backstage/frontend-test-utils@workspace:packages/frontend-test-utils" dependencies: "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" "@backstage/frontend-app-api": "workspace:^" "@backstage/frontend-plugin-api": "workspace:^" "@backstage/test-utils": "workspace:^" @@ -4577,13 +4585,13 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.28": - version: 1.1.28 - resolution: "@backstage/integration-react@npm:1.1.28" +"@backstage/integration-react@npm:^1.1.29": + version: 1.1.29 + resolution: "@backstage/integration-react@npm:1.1.29" dependencies: "@backstage/config": ^1.2.0 "@backstage/core-plugin-api": ^1.9.3 - "@backstage/integration": ^1.12.0 + "@backstage/integration": ^1.13.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@types/react": ^16.13.1 || ^17.0.0 @@ -4591,7 +4599,7 @@ __metadata: 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 + checksum: add10ad8c108933354037f9d74ec554174d2af53d74a031e12ed01e98bd51481413b93c694460cf045b3bae818dd18b5efa061fc60c210e145e4629e0cb227b7 languageName: node linkType: hard @@ -4619,9 +4627,9 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration@npm:^1.12.0": - version: 1.12.0 - resolution: "@backstage/integration@npm:1.12.0" +"@backstage/integration@npm:^1.13.0": + version: 1.13.0 + resolution: "@backstage/integration@npm:1.13.0" dependencies: "@azure/identity": ^4.0.0 "@backstage/config": ^1.2.0 @@ -4632,7 +4640,7 @@ __metadata: git-url-parse: ^14.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - checksum: 603c08058dadfe54b5d1788db87bab951b53ea4d1b19f609873717e0ab514859cc8608d0d60755c91eaea000ad71f817c5dd50892a3215443d7eed5a1d24a849 + checksum: 2b824261b0d30771e54515f8571c2af0b4c64f5cd3d1f990c234152b19e81d1e4ddbbbfae2a0b74f44abbfb67f52609c7eee9dc9fbb61d5f0076acaa80b3e670 languageName: node linkType: hard @@ -4689,7 +4697,7 @@ __metadata: "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/test-utils": "workspace:^" - "@graphiql/react": ^0.20.0 + "@graphiql/react": ^0.23.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 @@ -4739,7 +4747,7 @@ __metadata: knex: ^3.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 supertest: ^6.1.3 yn: ^4.0.0 languageName: unknown @@ -4809,7 +4817,7 @@ __metadata: jose: ^5.0.0 msw: ^2.0.8 node-cache: ^5.1.2 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 languageName: unknown linkType: soft @@ -4864,7 +4872,7 @@ __metadata: express: ^4.18.2 jose: ^5.0.0 msw: ^2.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 node-mocks-http: ^1.0.0 uuid: ^9.0.0 languageName: unknown @@ -4964,10 +4972,8 @@ __metadata: "@types/passport-microsoft": ^1.0.0 express: ^4.18.2 jose: ^5.0.0 - lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.6.7 - passport: ^0.7.0 + node-fetch: ^2.7.0 passport-microsoft: ^1.0.0 supertest: ^6.3.3 languageName: unknown @@ -5166,7 +5172,7 @@ __metadata: morgan: ^1.10.0 msw: ^1.0.0 node-cache: ^5.1.2 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 openid-client: ^5.2.1 passport: ^0.7.0 passport-auth0: ^1.4.3 @@ -5203,7 +5209,7 @@ __metadata: jose: ^5.0.0 lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 passport: ^0.7.0 supertest: ^6.1.3 uuid: ^9.0.0 @@ -5296,7 +5302,7 @@ __metadata: "@backstage/plugin-catalog-node": "workspace:^" luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 languageName: unknown linkType: soft @@ -5362,7 +5368,7 @@ __metadata: "@types/node-fetch": ^2.5.12 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 languageName: unknown linkType: soft @@ -5401,7 +5407,7 @@ __metadata: fs-extra: ^11.2.0 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 languageName: unknown linkType: soft @@ -5448,7 +5454,7 @@ __metadata: luxon: ^3.0.0 minimatch: ^9.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 languageName: unknown linkType: soft @@ -5492,7 +5498,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 languageName: unknown linkType: soft @@ -5578,7 +5584,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 p-limit: ^3.0.2 qs: ^6.9.4 uuid: ^9.0.0 @@ -5625,7 +5631,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 languageName: unknown linkType: soft @@ -5708,7 +5714,7 @@ __metadata: luxon: ^3.0.0 minimatch: ^9.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 p-limit: ^3.0.2 prom-client: ^15.0.0 supertest: ^6.1.3 @@ -5721,7 +5727,18 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@^1.0.20, @backstage/plugin-catalog-common@^1.0.24, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@npm:^1.0.20, @backstage/plugin-catalog-common@npm:^1.0.25": + version: 1.0.25 + resolution: "@backstage/plugin-catalog-common@npm:1.0.25" + dependencies: + "@backstage/catalog-model": ^1.5.0 + "@backstage/plugin-permission-common": ^0.8.0 + "@backstage/plugin-search-common": ^1.2.13 + checksum: 37078811a78423accc078ae43d1572de6e74e0daff6b03a3d6f30d3ce37e71d30f60ac90aea5cf442ca0d2123259b267b37b966e29aa4f2dba08845d562d0e68 + languageName: node + linkType: hard + +"@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: @@ -5830,20 +5847,20 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.11.3, @backstage/plugin-catalog-react@npm:^1.9.3": - version: 1.12.1 - resolution: "@backstage/plugin-catalog-react@npm:1.12.1" +"@backstage/plugin-catalog-react@npm:^1.12.2, @backstage/plugin-catalog-react@npm:^1.9.3": + version: 1.12.2 + resolution: "@backstage/plugin-catalog-react@npm:1.12.2" dependencies: "@backstage/catalog-client": ^1.6.5 "@backstage/catalog-model": ^1.5.0 - "@backstage/core-components": ^0.14.8 + "@backstage/core-components": ^0.14.9 "@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/frontend-plugin-api": ^0.6.7 + "@backstage/integration-react": ^1.1.29 + "@backstage/plugin-catalog-common": ^1.0.25 + "@backstage/plugin-permission-common": ^0.8.0 + "@backstage/plugin-permission-react": ^0.4.24 "@backstage/types": ^1.1.1 "@backstage/version-bridge": ^1.0.8 "@material-ui/core": ^4.12.2 @@ -5862,7 +5879,7 @@ __metadata: 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 + checksum: 8570e71e56e89cc8ba890ad9cd1f2ce22147635e9a326703291ee8a75d704086c4a31cd11b2b2c3eb54f3e1dc82822b1bc7b9317e8c6d81f6ab9758c2c01ec5a languageName: node linkType: hard @@ -6048,7 +6065,7 @@ __metadata: express-promise-router: ^4.1.0 fs-extra: ^11.0.0 lodash: ^4.17.21 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 ping: ^0.4.1 semver: ^7.5.3 supertest: ^6.2.4 @@ -6323,7 +6340,7 @@ __metadata: luxon: ^3.0.0 morgan: ^1.10.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 stream-buffers: ^3.0.2 supertest: ^6.1.3 winston: ^3.2.1 @@ -6396,7 +6413,7 @@ __metadata: "@backstage/types": "workspace:^" "@kubernetes/client-node": ^0.20.0 msw: ^1.3.1 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 supertest: ^6.1.3 winston: ^3.2.1 languageName: unknown @@ -6446,9 +6463,11 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-kubernetes-common": "workspace:^" "@backstage/plugin-kubernetes-react": "workspace:^" @@ -6528,7 +6547,7 @@ __metadata: express-promise-router: ^4.1.0 knex: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 supertest: ^6.2.4 uuid: ^9.0.0 winston: ^3.2.1 @@ -6561,7 +6580,7 @@ __metadata: "@backstage/test-utils": "workspace:^" knex: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 languageName: unknown linkType: soft @@ -6703,14 +6722,28 @@ __metadata: express-promise-router: ^4.1.0 lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 supertest: ^6.1.6 yn: ^4.0.0 zod: ^3.22.4 languageName: unknown linkType: soft -"@backstage/plugin-permission-common@^0.7.14, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@npm:^0.8.0": + version: 0.8.0 + resolution: "@backstage/plugin-permission-common@npm:0.8.0" + dependencies: + "@backstage/config": ^1.2.0 + "@backstage/errors": ^1.2.4 + "@backstage/types": ^1.1.1 + cross-fetch: ^4.0.0 + uuid: ^9.0.0 + zod: ^3.22.4 + checksum: 03d706cf764d65319fd32156438b6f826568c7d51e79fc6e7cd951b023017a1e07c7380f2babec7efd2ed96f441485ee68072d06fb5e42a1bf7aba7cd1f6ce6f + languageName: node + linkType: hard + +"@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: @@ -6722,6 +6755,7 @@ __metadata: msw: ^1.0.0 uuid: ^9.0.0 zod: ^3.22.4 + zod-to-json-schema: ^3.20.4 languageName: unknown linkType: soft @@ -6748,7 +6782,24 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@^0.4.23, @backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": +"@backstage/plugin-permission-react@npm:^0.4.24": + version: 0.4.24 + resolution: "@backstage/plugin-permission-react@npm:0.4.24" + dependencies: + "@backstage/config": ^1.2.0 + "@backstage/core-plugin-api": ^1.9.3 + "@backstage/plugin-permission-common": ^0.8.0 + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + swr: ^2.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: 6fa895f4a25f7f08642f64a9b4b41e5f3adfbf3c3f1ede9e1abc7bb08f532d9d0c9baf9f08b472fff54803a2c2aaeff2306b5e6d1514193a2407af4b12433d3a + languageName: node + linkType: hard + +"@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: @@ -6791,7 +6842,7 @@ __metadata: http-proxy-middleware: ^2.0.0 morgan: ^1.10.0 msw: ^2.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 uuid: ^9.0.0 winston: ^3.2.1 yaml: ^2.0.0 @@ -6831,7 +6882,7 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" fs-extra: ^11.2.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -6850,7 +6901,7 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" fs-extra: ^11.2.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -6871,7 +6922,7 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" fs-extra: ^11.2.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -6892,7 +6943,7 @@ __metadata: fs-extra: ^11.2.0 git-url-parse: ^14.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 node-html-markdown: ^1.3.0 yaml: ^2.0.0 languageName: unknown @@ -6917,6 +6968,7 @@ __metadata: command-exists: ^1.2.9 fs-extra: ^11.2.0 winston: ^3.2.1 + yaml: ^2.0.0 yn: ^4.0.0 languageName: unknown linkType: soft @@ -6950,7 +7002,7 @@ __metadata: "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -6968,7 +7020,7 @@ __metadata: "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7032,6 +7084,7 @@ __metadata: "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" octokit: ^3.0.0 + yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7055,6 +7108,7 @@ __metadata: command-exists: ^1.2.9 fs-extra: ^11.0.0 jest-when: ^3.1.0 + yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7071,7 +7125,7 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" "@backstage/types": "workspace:^" msw: ^2.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 yaml: ^2.3.3 languageName: unknown linkType: soft @@ -7249,6 +7303,7 @@ __metadata: "@types/json-schema": ^7.0.9 "@types/luxon": ^3.0.0 "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + ajv-errors: ^3.0.0 classnames: ^2.2.6 flatted: 3.3.1 humanize-duration: ^3.25.1 @@ -7392,7 +7447,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-search-backend-module-explore@workspace:plugins/search-backend-module-explore" dependencies: - "@backstage-community/plugin-explore-common": ^0.0.3 + "@backstage-community/plugin-explore-common": ^0.0.4 "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^" @@ -7402,7 +7457,7 @@ __metadata: "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" msw: ^1.2.1 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 languageName: unknown linkType: soft @@ -7410,7 +7465,6 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-search-backend-module-pg@workspace:plugins/search-backend-module-pg" dependencies: - "@backstage/backend-app-api": "workspace:^" "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" @@ -7438,7 +7492,7 @@ __metadata: "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" msw: ^1.2.1 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 qs: ^6.9.4 languageName: unknown linkType: soft @@ -7463,7 +7517,7 @@ __metadata: "@backstage/plugin-techdocs-node": "workspace:^" lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 p-limit: ^3.1.0 languageName: unknown linkType: soft @@ -7521,6 +7575,16 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-search-common@npm:^1.2.13": + version: 1.2.13 + resolution: "@backstage/plugin-search-common@npm:1.2.13" + dependencies: + "@backstage/plugin-permission-common": ^0.8.0 + "@backstage/types": ^1.1.1 + checksum: 0c7b7b791b648e874081b845488f636791754bc4da1a4780b49e7281cc6294bcad0a9feab9fd7dd5f6a583b5fce372e704f440ad7bc33ab828ebd2afc5344504 + languageName: node + linkType: hard + "@backstage/plugin-search-common@workspace:^, @backstage/plugin-search-common@workspace:plugins/search-common": version: 0.0.0-use.local resolution: "@backstage/plugin-search-common@workspace:plugins/search-common" @@ -7624,7 +7688,7 @@ __metadata: express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 supertest: ^6.2.4 uuid: ^9.0.0 winston: ^3.2.1 @@ -7738,6 +7802,7 @@ __metadata: "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-search-backend-module-techdocs": "workspace:^" + "@backstage/plugin-techdocs-common": "workspace:^" "@backstage/plugin-techdocs-node": "workspace:^" "@types/express": ^4.17.6 express: ^4.17.1 @@ -7746,13 +7811,21 @@ __metadata: knex: ^3.0.0 lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.6.7 + node-fetch: ^2.7.0 p-limit: ^3.1.0 supertest: ^6.1.3 winston: ^3.2.1 languageName: unknown linkType: soft +"@backstage/plugin-techdocs-common@workspace:^, @backstage/plugin-techdocs-common@workspace:plugins/techdocs-common": + version: 0.0.0-use.local + resolution: "@backstage/plugin-techdocs-common@workspace:plugins/techdocs-common" + dependencies: + "@backstage/cli": "workspace:^" + languageName: unknown + linkType: soft + "@backstage/plugin-techdocs-module-addons-contrib@workspace:^, @backstage/plugin-techdocs-module-addons-contrib@workspace:plugins/techdocs-module-addons-contrib": version: 0.0.0-use.local resolution: "@backstage/plugin-techdocs-module-addons-contrib@workspace:plugins/techdocs-module-addons-contrib" @@ -7801,6 +7874,7 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/integration-aws-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" + "@backstage/plugin-techdocs-common": "workspace:^" "@google-cloud/storage": ^7.0.0 "@smithy/node-http-handler": ^2.1.7 "@trendyol-js/openstack-swift-sdk": ^0.0.7 @@ -7874,6 +7948,7 @@ __metadata: "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-search-react": "workspace:^" + "@backstage/plugin-techdocs-common": "workspace:^" "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^" "@backstage/plugin-techdocs-react": "workspace:^" "@backstage/test-utils": "workspace:^" @@ -8156,12 +8231,12 @@ __metadata: languageName: node linkType: hard -"@changesets/apply-release-plan@npm:^7.0.3": - version: 7.0.3 - resolution: "@changesets/apply-release-plan@npm:7.0.3" +"@changesets/apply-release-plan@npm:^7.0.4": + version: 7.0.4 + resolution: "@changesets/apply-release-plan@npm:7.0.4" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/config": ^3.0.1 + "@changesets/config": ^3.0.2 "@changesets/get-version-range-type": ^0.4.0 "@changesets/git": ^3.0.0 "@changesets/should-skip-package": ^0.1.0 @@ -8174,22 +8249,22 @@ __metadata: prettier: ^2.7.1 resolve-from: ^5.0.0 semver: ^7.5.3 - checksum: 622b1ed7652b072b28bee431d5407ce686cff058caa3db9353848cd1177dc535d352711f6e5f9f819a7331235e72279f7e0f34955da67681c50d051ec30f476a + checksum: 5a61a8794fd4762e9270ffec474dc7c5d420c1d0479c5316a12e5264589882ccfb3ec08af6c0ebd07de2bf26ae880ad2f65e8f16d5886745aecf48cb11f625f5 languageName: node linkType: hard -"@changesets/assemble-release-plan@npm:^6.0.2": - version: 6.0.2 - resolution: "@changesets/assemble-release-plan@npm:6.0.2" +"@changesets/assemble-release-plan@npm:^6.0.3": + version: 6.0.3 + resolution: "@changesets/assemble-release-plan@npm:6.0.3" dependencies: "@babel/runtime": ^7.20.1 "@changesets/errors": ^0.2.0 - "@changesets/get-dependents-graph": ^2.1.0 + "@changesets/get-dependents-graph": ^2.1.1 "@changesets/should-skip-package": ^0.1.0 "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 semver: ^7.5.3 - checksum: 90019a9bd22ad1368f23f1335d1b7eea5a55b1ed8b9141c9cc2fdab99bda85f9cb3886062a33c078cfb6f08f1a6f165aedbb1d1ce2a63c15ce0bfa7a7c365854 + checksum: ae0ac29a44640fc6c0d3782c134adad3f0af80903ecb8bf663f0bf5f569586c9620980100737a05639f1a7252f145942ae62fa25d0757e89b5d6311abf899cd5 languageName: node linkType: hard @@ -8203,17 +8278,17 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.27.6 - resolution: "@changesets/cli@npm:2.27.6" + version: 2.27.7 + resolution: "@changesets/cli@npm:2.27.7" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/apply-release-plan": ^7.0.3 - "@changesets/assemble-release-plan": ^6.0.2 + "@changesets/apply-release-plan": ^7.0.4 + "@changesets/assemble-release-plan": ^6.0.3 "@changesets/changelog-git": ^0.2.0 - "@changesets/config": ^3.0.1 + "@changesets/config": ^3.0.2 "@changesets/errors": ^0.2.0 - "@changesets/get-dependents-graph": ^2.1.0 - "@changesets/get-release-plan": ^4.0.2 + "@changesets/get-dependents-graph": ^2.1.1 + "@changesets/get-release-plan": ^4.0.3 "@changesets/git": ^3.0.0 "@changesets/logger": ^0.1.0 "@changesets/pre": ^2.0.0 @@ -8240,22 +8315,22 @@ __metadata: term-size: ^2.1.0 bin: changeset: bin.js - checksum: efb3c7b569debb2bb0baae2d7bafee4ae19d3c7f0023ea97fa0b6518198c85ba16c2a66609561c9dd0f0601c3390d5933b00e3ad3cb962b4b0e7fcb4de929dfa + checksum: f518121a516ce8186dfc71dcca2f4be5fea28fe29a54b038aa787964bb4d4f1e866840d6d765776db33f7723d1a850ee4a38ed726f302a26e2e56a5e2b9422e8 languageName: node linkType: hard -"@changesets/config@npm:^3.0.1": - version: 3.0.1 - resolution: "@changesets/config@npm:3.0.1" +"@changesets/config@npm:^3.0.2": + version: 3.0.2 + resolution: "@changesets/config@npm:3.0.2" dependencies: "@changesets/errors": ^0.2.0 - "@changesets/get-dependents-graph": ^2.1.0 + "@changesets/get-dependents-graph": ^2.1.1 "@changesets/logger": ^0.1.0 "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 fs-extra: ^7.0.1 micromatch: ^4.0.2 - checksum: 588a8139f721e2917c9bad842e3a933a8a5216b6a73c6a203ddcb834c274f873eaa780b32b42f89a477159e898ad3c1c93ca0ac28a07401b7b3f56185672a6a8 + checksum: 4160e59f74c1f36a2d3d011868f83c46410553f9fc164a83dde46ec7e37f13ba983526b9c299de3cd3f317e5e42808a991959931c9d34f2913f3e8d4c515cd12 languageName: node linkType: hard @@ -8268,31 +8343,31 @@ __metadata: languageName: node linkType: hard -"@changesets/get-dependents-graph@npm:^2.1.0": - version: 2.1.0 - resolution: "@changesets/get-dependents-graph@npm:2.1.0" +"@changesets/get-dependents-graph@npm:^2.1.1": + version: 2.1.1 + resolution: "@changesets/get-dependents-graph@npm:2.1.1" dependencies: "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 chalk: ^2.1.0 fs-extra: ^7.0.1 semver: ^7.5.3 - checksum: 1cd9c0f145a20d735ab9e1d615c5bdf52179cd2fc9b8555649d74979d8dbc915f9e85af4e20f7b71da76d3d860cd2090cee4c6ecccac4f5bf42ae11bb245471d + checksum: e427603a3cad3690deec86a5831f15766dc32dc0819532e3ad70fbda027317bb46bb207c6a3bc947daf00e5e8229a01dd67aa3ec7248aa11f87611a7ecd74097 languageName: node linkType: hard -"@changesets/get-release-plan@npm:^4.0.2": - version: 4.0.2 - resolution: "@changesets/get-release-plan@npm:4.0.2" +"@changesets/get-release-plan@npm:^4.0.3": + version: 4.0.3 + resolution: "@changesets/get-release-plan@npm:4.0.3" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/assemble-release-plan": ^6.0.2 - "@changesets/config": ^3.0.1 + "@changesets/assemble-release-plan": ^6.0.3 + "@changesets/config": ^3.0.2 "@changesets/pre": ^2.0.0 "@changesets/read": ^0.6.0 "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 - checksum: 651814230890bf7605f4094332e4842505eb060092fbe65d9c8fa1a44f724ce0086890b8437f2fa96aedfa11c88e622e133d700847dea4c92141c2fbb486460f + checksum: baf01eb124f95df729e1798c23e4ac1996acd74e0d22336492e4a0fd68f3a19c97197337fdcb58d47d0b580ca38e0b0888cbacaa1c99d7c173c3cecb859ab4cc languageName: node linkType: hard @@ -9480,14 +9555,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 @@ -9538,7 +9613,7 @@ __metadata: languageName: node linkType: hard -"@graphiql/react@npm:^0.20.0, @graphiql/react@npm:^0.20.3": +"@graphiql/react@npm:^0.20.3": version: 0.20.3 resolution: "@graphiql/react@npm:0.20.3" dependencies: @@ -9565,9 +9640,36 @@ __metadata: languageName: node linkType: hard -"@graphiql/toolkit@npm:^0.9.1": - version: 0.9.1 - resolution: "@graphiql/toolkit@npm:0.9.1" +"@graphiql/react@npm:^0.23.0": + version: 0.23.0 + resolution: "@graphiql/react@npm:0.23.0" + dependencies: + "@graphiql/toolkit": ^0.9.2 + "@headlessui/react": ^1.7.15 + "@radix-ui/react-dialog": ^1.0.4 + "@radix-ui/react-dropdown-menu": ^2.0.5 + "@radix-ui/react-tooltip": ^1.0.6 + "@radix-ui/react-visually-hidden": ^1.0.3 + "@types/codemirror": ^5.60.8 + clsx: ^1.2.1 + codemirror: ^5.65.3 + codemirror-graphql: ^2.0.13 + copy-to-clipboard: ^3.2.0 + framer-motion: ^6.5.1 + graphql-language-service: ^5.2.2 + markdown-it: ^14.1.0 + set-value: ^4.1.0 + peerDependencies: + graphql: ^15.5.0 || ^16.0.0 + react: ^16.8.0 || ^17 || ^18 + react-dom: ^16.8.0 || ^17 || ^18 + checksum: a62ee7d763d410f5ff8c5670596194069e97f11b906762c4e38c74797e4e34c33cd91e06aae24d5118e0fa05dc6c1ffa6c3d3d8ff5bc2b6af0b689088236f613 + languageName: node + linkType: hard + +"@graphiql/toolkit@npm:^0.9.1, @graphiql/toolkit@npm:^0.9.2": + version: 0.9.2 + resolution: "@graphiql/toolkit@npm:0.9.2" dependencies: "@n1ru4l/push-pull-async-iterable-iterator": ^3.1.0 meros: ^1.1.4 @@ -9577,7 +9679,7 @@ __metadata: peerDependenciesMeta: graphql-ws: optional: true - checksum: 5328426051b7f9a9ffbd569c950d1a103ce0e2ee7b5d7a57f3d899488ad43d1a5101e8aeced7416e106c7687d67bb7981aa7e87dea5b0f17b77569aa738bf3b5 + checksum: 4474a998a948d0df5cef8371245b0e895be40803a07e49231ab91798aa761880e6e4a684478a44b723c013f0e8206dab3d86e5b0fc9b688df035fa9f1fa29734 languageName: node linkType: hard @@ -9865,27 +9967,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: @@ -11040,6 +11132,145 @@ __metadata: languageName: node linkType: hard +"@module-federation/dts-plugin@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/dts-plugin@npm:0.1.21" + dependencies: + "@module-federation/managers": 0.1.21 + "@module-federation/sdk": 0.1.21 + "@module-federation/third-party-dts-extractor": 0.1.21 + adm-zip: ^0.5.10 + ansi-colors: ^4.1.3 + axios: ^1.6.7 + chalk: 3.0.0 + fs-extra: 9.1.0 + isomorphic-ws: 5.0.0 + koa: 2.11.0 + lodash.clonedeepwith: 4.5.0 + log4js: 6.9.1 + node-schedule: 2.1.1 + rambda: ^9.1.0 + ws: 8.17.0 + peerDependencies: + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: ^1.0.24 + peerDependenciesMeta: + vue-tsc: + optional: true + checksum: ec4cd030a25617698754cbac2da5463f8942cdd0a64bdc95f6ff5fd29fff6b88cf3db90e53e6b260cd3593893fe6ee2d6e149d0a46698eb7f9cc19a9df26193d + languageName: node + linkType: hard + +"@module-federation/enhanced@npm:^0.1.19": + version: 0.1.21 + resolution: "@module-federation/enhanced@npm:0.1.21" + dependencies: + "@module-federation/dts-plugin": 0.1.21 + "@module-federation/managers": 0.1.21 + "@module-federation/manifest": 0.1.21 + "@module-federation/rspack": 0.1.21 + "@module-federation/runtime-tools": 0.1.21 + "@module-federation/sdk": 0.1.21 + upath: 2.0.1 + peerDependencies: + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: ^1.0.24 + webpack: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + vue-tsc: + optional: true + webpack: + optional: true + checksum: bc0ff541db1066b290b3ad9ab868437dc3d0754b9d06ab263f8fb7f54e08238eae9232a482a681dd6152e4a175578d65df9f27fe181fc8fb602d7cc1ae34807d + languageName: node + linkType: hard + +"@module-federation/managers@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/managers@npm:0.1.21" + dependencies: + "@module-federation/sdk": 0.1.21 + find-pkg: 2.0.0 + fs-extra: 9.1.0 + checksum: 5f230d5795d86dfd68c404ee2b7a1264950c283a4b1c6f4ee9cc9579fabb413718dfbc1ff726b9c213f9d3223d944dd38dd9d04b700962e6398c3c3728d6323e + languageName: node + linkType: hard + +"@module-federation/manifest@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/manifest@npm:0.1.21" + dependencies: + "@module-federation/dts-plugin": 0.1.21 + "@module-federation/managers": 0.1.21 + "@module-federation/sdk": 0.1.21 + chalk: 3.0.0 + find-pkg: 2.0.0 + checksum: cef2011875f14e853a355626ae1dbc8ae3b0714d31140e329b5dd71525782b08c2e1d6ca45276a563bb3c3b7f7c4e64a31f0698ef12606f05aa6da46e759f345 + languageName: node + linkType: hard + +"@module-federation/rspack@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/rspack@npm:0.1.21" + dependencies: + "@module-federation/dts-plugin": 0.1.21 + "@module-federation/managers": 0.1.21 + "@module-federation/manifest": 0.1.21 + "@module-federation/runtime-tools": 0.1.21 + "@module-federation/sdk": 0.1.21 + checksum: 55516285e23f4ca7127afafb14af667defbe46dc3224f85d7e07edbc8937d7fac909dfebc2f9dd73120b99bbe5135372cf0fbbe282990d80e6953a60dfa4c93e + languageName: node + linkType: hard + +"@module-federation/runtime-tools@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/runtime-tools@npm:0.1.21" + dependencies: + "@module-federation/runtime": 0.1.21 + "@module-federation/webpack-bundler-runtime": 0.1.21 + checksum: 628c0c4834093520f9c71481d587c9e18163f82e481b05b1900f04e2d5da4abb69af6d814ac5cd1951057b28d73f3adeb1cee7cd83628305b10cc7988405fbc5 + languageName: node + linkType: hard + +"@module-federation/runtime@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/runtime@npm:0.1.21" + dependencies: + "@module-federation/sdk": 0.1.21 + checksum: ce4de8515b54f1cd07a3c7c4cbd35fea163294b9fb24be10827872f3ebb62cd5c289f3602efe4149d963282739f79b51947afa039ee6f36be7f66dea83d590fc + languageName: node + linkType: hard + +"@module-federation/sdk@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/sdk@npm:0.1.21" + checksum: 6856dcfe2ef5ae939890b82010aaad911fa6c4330a05f290ae054c316c9b532d3691456a1f9e176fe05f1df2d6f2d8c7e0c842ca5648a0fd7abf270e44ed9ecb + languageName: node + linkType: hard + +"@module-federation/third-party-dts-extractor@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/third-party-dts-extractor@npm:0.1.21" + dependencies: + find-pkg: 2.0.0 + fs-extra: 9.1.0 + resolve: 1.22.8 + checksum: e394fd7c2e6dbdf8df6937628680e7356ac897ee6f1309d7fbc38c00bcf4be9c0363f8bc1a75c29f7987a5a2f11f7855481813889b18e8b444ee9006aeb4a299 + languageName: node + linkType: hard + +"@module-federation/webpack-bundler-runtime@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/webpack-bundler-runtime@npm:0.1.21" + dependencies: + "@module-federation/runtime": 0.1.21 + "@module-federation/sdk": 0.1.21 + checksum: 7d96002066e63bdb503964fd5fb2798be25f4135a599d87721f4d26ebe1de1affbf447c56b082f7ee850ae7798d0ac637f6a486f58591269065e114051b466e5 + languageName: node + linkType: hard + "@motionone/animation@npm:^10.12.0": version: 10.16.3 resolution: "@motionone/animation@npm:10.16.3" @@ -12109,6 +12340,13 @@ __metadata: languageName: node linkType: hard +"@octokit/openapi-types@npm:^22.2.0": + version: 22.2.0 + resolution: "@octokit/openapi-types@npm:22.2.0" + checksum: eca41feac2b83298e0d95e253ac1c5b6d65155ac57f65c5fd8d4a485d9728922d85ff4bee0e815a1f3a5421311db092bdb6da9d6104a1b1843d8b274bcad9630 + languageName: node + linkType: hard + "@octokit/plugin-paginate-graphql@npm:^4.0.0": version: 4.0.0 resolution: "@octokit/plugin-paginate-graphql@npm:4.0.0" @@ -12118,6 +12356,17 @@ __metadata: languageName: node linkType: hard +"@octokit/plugin-paginate-rest@npm:11.3.1": + version: 11.3.1 + resolution: "@octokit/plugin-paginate-rest@npm:11.3.1" + dependencies: + "@octokit/types": ^13.5.0 + peerDependencies: + "@octokit/core": 5 + checksum: 42c7c08e7287b4b85d2ae47852d2ffeb238c134ad6bcff18bddc154b15f6bec31778816c0763181401c370198390db7f6b0c3c44750fdfeec459594f7f4b5933 + languageName: node + linkType: hard + "@octokit/plugin-paginate-rest@npm:^6.1.2": version: 6.1.2 resolution: "@octokit/plugin-paginate-rest@npm:6.1.2" @@ -12150,14 +12399,14 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-rest-endpoint-methods@npm:^10.0.0": - version: 10.2.0 - resolution: "@octokit/plugin-rest-endpoint-methods@npm:10.2.0" +"@octokit/plugin-rest-endpoint-methods@npm:13.2.2": + version: 13.2.2 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.2.2" dependencies: - "@octokit/types": ^12.3.0 + "@octokit/types": ^13.5.0 peerDependencies: - "@octokit/core": ">=5" - checksum: 3209688bf508d22a525fe32d632ff928b048688c1859c7e4bbb08bd181aa07f580b375a502e34368628103e5d5cccf7f9fb0ff0c8fd4262470ac8eeffb80ac6b + "@octokit/core": ^5 + checksum: 347b3a891a561ed1dcc307a2dce42ca48c318c465ad91a26225d3d6493aef1b7ff868e6c56a0d7aa4170d028c7429ca1ec52aed6be34615a6ed701c3bcafdb17 languageName: node linkType: hard @@ -12290,7 +12539,7 @@ __metadata: languageName: node linkType: hard -"@octokit/types@npm:^12.0.0, @octokit/types@npm:^12.2.0, @octokit/types@npm:^12.3.0, @octokit/types@npm:^12.4.0": +"@octokit/types@npm:^12.0.0, @octokit/types@npm:^12.2.0, @octokit/types@npm:^12.4.0": version: 12.4.0 resolution: "@octokit/types@npm:12.4.0" dependencies: @@ -12299,6 +12548,15 @@ __metadata: languageName: node linkType: hard +"@octokit/types@npm:^13.0.0, @octokit/types@npm:^13.5.0": + version: 13.5.0 + resolution: "@octokit/types@npm:13.5.0" + dependencies: + "@octokit/openapi-types": ^22.2.0 + checksum: 8e92f2b145b3c28a35312f93714245824a7b6b7353caa88edfdc85fc2ed4108321ed0c3988001ea53449fbb212febe0e8e9582744e85c3574dabe9d0441af5a0 + languageName: node + linkType: hard + "@octokit/types@npm:^6.0.3, @octokit/types@npm:^6.10.0, @octokit/types@npm:^6.12.2, @octokit/types@npm:^6.16.1": version: 6.41.0 resolution: "@octokit/types@npm:6.41.0" @@ -13739,13 +13997,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.45.0 - resolution: "@playwright/test@npm:1.45.0" + version: 1.45.3 + resolution: "@playwright/test@npm:1.45.3" dependencies: - playwright: 1.45.0 + playwright: 1.45.3 bin: playwright: cli.js - checksum: 55fb72f393b05f6684b5098e0681712f71e1fe25aa6a00bd636133f9ccc26d096d61ee30f569b83368e4bf6a1288d2f8f6fd5364da5d396eab180f89f61b7164 + checksum: 3e2c88d40f98cf94ab7947263804d1ee78c4bb21a35c8dbb64855eed5565ffc688509c5f07bda5438cba6c354374981448dcba3dbe326d1699b4fef75c9ce43d languageName: node linkType: hard @@ -15006,13 +15264,13 @@ __metadata: languageName: node linkType: hard -"@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" +"@smithy/abort-controller@npm:^3.1.1": + version: 3.1.1 + resolution: "@smithy/abort-controller@npm:3.1.1" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 78643bddda2bcb68e00bb95ae866741407236b92b1834796c0855710950386ae1e5e67d72fb42ec444e8a4dc4357a1527c4f331324a2fad156468f5a0cccf128 + checksum: 7b7497f49d58787cad858f8c5ea9931ccd44d39536db4abdd531a5abf37784469522e41d9ad1d541892caa0ed3bea750447809a0a18f4689a9543d672aa61d48 languageName: node linkType: hard @@ -15035,158 +15293,158 @@ __metadata: languageName: node linkType: hard -"@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" +"@smithy/config-resolver@npm:^3.0.5": + version: 3.0.5 + resolution: "@smithy/config-resolver@npm:3.0.5" dependencies: - "@smithy/node-config-provider": ^3.1.2 - "@smithy/types": ^3.2.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 "@smithy/util-config-provider": ^3.0.0 - "@smithy/util-middleware": ^3.0.2 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: 7a7baf23e64ed85d4229bfd320a3ea96087c57ce1b94638a89bab5f92dcc24ec22c11740d90f2fab38eb39eeb860463ae98b24598555c2b55a01bd79c20ef99b + checksum: 96895ae0622a229655fa08f009d29a20157043020125014e84cb5ca33a10171c9724c309491214c2422d9c4c6681e7f5ec5f7faa8f45e11250449cf07f3552ec languageName: node linkType: hard -"@smithy/core@npm:^2.2.1": - version: 2.2.3 - resolution: "@smithy/core@npm:2.2.3" +"@smithy/core@npm:^2.3.1": + version: 2.3.1 + resolution: "@smithy/core@npm:2.3.1" dependencies: - "@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 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.13 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: 6addaede7f4699c48d690872647bbc86efc5bf9adb088557cfd4263e629e6bd7d45a1de983824a7c5ff608ec2cd42d7c6f61854d3d33b8ded352df550789b34b + checksum: f191a36742a08c6898f4aaa43335bfb96cdca9a9099c0608fb0ef151917816b03ee1b27ef3720d89fba90d2d24fedfb47478f837d47c1c2e5ff8ceeb844ec7d6 languageName: node linkType: hard -"@smithy/credential-provider-imds@npm:^3.1.1, @smithy/credential-provider-imds@npm:^3.1.2": +"@smithy/credential-provider-imds@npm:^3.2.0": + version: 3.2.0 + resolution: "@smithy/credential-provider-imds@npm:3.2.0" + dependencies: + "@smithy/node-config-provider": ^3.1.4 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + tslib: ^2.6.2 + checksum: fc79919133008db91a83f2caf6eba11d704f34af5fa3dd1f7b8cc048214e805d9f20a3f302f5ed4862ee6b6c3bb28ff3a5d8c77d2f497d10f3be14915e59debe + languageName: node + linkType: hard + +"@smithy/eventstream-codec@npm:^3.1.2": version: 3.1.2 - resolution: "@smithy/credential-provider-imds@npm:3.1.2" - dependencies: - "@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: bf0ce9f7c510f5f7e05d08c2b1d861f133016457e3872bfc5e4ac9b22f26123adcf773a562189971e2ce97bdad2f576a4eefb764808df2ae1833e77be86358f2 - languageName: node - linkType: hard - -"@smithy/eventstream-codec@npm:^3.1.1": - version: 3.1.1 - resolution: "@smithy/eventstream-codec@npm:3.1.1" + resolution: "@smithy/eventstream-codec@npm:3.1.2" dependencies: "@aws-crypto/crc32": 5.2.0 - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 "@smithy/util-hex-encoding": ^3.0.0 tslib: ^2.6.2 - checksum: fdc7a2bcf99f7c830ba24b5745877ec26556613423a025c6b122b167ef92a76a860f7dffe21f25667f12c2736a121f4e2064050dcf768406a60ce3ebc029e402 + checksum: b0c836acbf59b57a7e2ef948a54bd441d11b75d70f1c334723c27fce1ab0ff93ea9f936976b754272b5e90413b5a169c60b1df7ecfd7d061ebaae8d5cc067d94 languageName: node linkType: hard -"@smithy/eventstream-serde-browser@npm:^3.0.2": +"@smithy/eventstream-serde-browser@npm:^3.0.5": + version: 3.0.5 + resolution: "@smithy/eventstream-serde-browser@npm:3.0.5" + dependencies: + "@smithy/eventstream-serde-universal": ^3.0.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 14e8a2027745e7a1ad261068e792e4a660043ce53fefc5f564b38b841ba02d40992b38fbd2357e762f0a1ecb658df3bbf23cf5ef33c3ec2488d316be95b61b9e + languageName: node + linkType: hard + +"@smithy/eventstream-serde-config-resolver@npm:^3.0.3": version: 3.0.3 - resolution: "@smithy/eventstream-serde-browser@npm:3.0.3" + resolution: "@smithy/eventstream-serde-config-resolver@npm:3.0.3" dependencies: - "@smithy/eventstream-serde-universal": ^3.0.3 - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 3e41fb32f06dc266ab41185482e441068c1e84ac5637462fc107511a495a7338972f10568bb57970e22eef2d14e024f93e0991b30b54545bca5b5189add5d41e + checksum: c61780aa0ad8c479618d0b3fcb2b42f1f9a74dcf814dba08305107ed1f088f56aa1c346db9c72439ff18617f31b9c59c6895060e4c9765c81d759150a22674af languageName: node linkType: hard -"@smithy/eventstream-serde-config-resolver@npm:^3.0.1": - version: 3.0.2 - resolution: "@smithy/eventstream-serde-config-resolver@npm:3.0.2" +"@smithy/eventstream-serde-node@npm:^3.0.4": + version: 3.0.4 + resolution: "@smithy/eventstream-serde-node@npm:3.0.4" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/eventstream-serde-universal": ^3.0.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 5c2113b6acc65df61f6fc844054c5a85825305e1d9f47987a5f350b603e304c8d90ad2c62cb7a098f10b7243c4f466fa413264821d261a3b69dc12c33fa976d4 + checksum: 0a75b184d95ab8c08efd93bf32c5fd9d735b5879df556599bd2ab78f23e3f77452e597bbdd42586c9bbedcc2b0b7683de4c816db739c19a2ebd62a34096ca86d languageName: node linkType: hard -"@smithy/eventstream-serde-node@npm:^3.0.2": - version: 3.0.3 - resolution: "@smithy/eventstream-serde-node@npm:3.0.3" +"@smithy/eventstream-serde-universal@npm:^3.0.4": + version: 3.0.4 + resolution: "@smithy/eventstream-serde-universal@npm:3.0.4" dependencies: - "@smithy/eventstream-serde-universal": ^3.0.3 - "@smithy/types": ^3.2.0 + "@smithy/eventstream-codec": ^3.1.2 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 29e2323b92a87302518ecfd75096e856c77a3d39ffa2680ff56e11c2c01b4434f56f86940e13c636e207af7cadf867f824f5c60249c53e1c27faa1cf932b6eb9 + checksum: 8463403ca4caf4ad48dba89b126f394439a289c9095ce6361c1f186c6021c1cd8ea402d1ce06b7284069c3415091ae4d802f66ded1b89e9da9d4c255b8402668 languageName: node linkType: hard -"@smithy/eventstream-serde-universal@npm:^3.0.3": - version: 3.0.3 - resolution: "@smithy/eventstream-serde-universal@npm:3.0.3" +"@smithy/fetch-http-handler@npm:^3.2.4": + version: 3.2.4 + resolution: "@smithy/fetch-http-handler@npm:3.2.4" dependencies: - "@smithy/eventstream-codec": ^3.1.1 - "@smithy/types": ^3.2.0 - tslib: ^2.6.2 - checksum: 6c0c3602e3e79bb0abe47f1d7b8c277f58879ab613cda99d80cf0e825653055f892daee313e6d40e5096932e004838e3c9f674e440b97921520257f80337bed8 - languageName: node - linkType: hard - -"@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/protocol-http": ^4.0.2 - "@smithy/querystring-builder": ^3.0.2 - "@smithy/types": ^3.2.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/querystring-builder": ^3.0.3 + "@smithy/types": ^3.3.0 "@smithy/util-base64": ^3.0.0 tslib: ^2.6.2 - checksum: 7b9b928e8a094e41a9c7516aa2fcfd3bb88b0271737e1d4fa301973a49f577094fa967ba481a0cf6e5c977be6bb8b2898d868b3269a476cae2aaaed582277733 + checksum: 73df885c637c14353f449678a4e109aeb19945c5370a615793ca2a54a29746a78e725e324b01cfd86fc71f4afd6386da2758fccc49d247a623ecbe70f607cb74 languageName: node linkType: hard -"@smithy/hash-blob-browser@npm:^3.1.0": - version: 3.1.1 - resolution: "@smithy/hash-blob-browser@npm:3.1.1" +"@smithy/hash-blob-browser@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/hash-blob-browser@npm:3.1.2" dependencies: "@smithy/chunked-blob-reader": ^3.0.0 "@smithy/chunked-blob-reader-native": ^3.0.0 - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 9a54f0b7d48d5a411c2e3361f8a946d71b75d54965bc3d2a0524d0fe01fc032c2ee2a4e105104daefa14e3e02f0e38b9e83faf0b40d3933a33b87d8b8b142c8f + checksum: 959ec975cd4b3d86e3d0288e24b460343795bc305ef38fc43f8485cd1440da4068d375c5d1dab73ae875f02e861f194512a7adf5afcd7395bbeb97897d8a809b languageName: node linkType: hard -"@smithy/hash-node@npm:^3.0.1": - version: 3.0.2 - resolution: "@smithy/hash-node@npm:3.0.2" +"@smithy/hash-node@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/hash-node@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 "@smithy/util-buffer-from": ^3.0.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 2b7b678d429b9806a28f18472f8beec45f5a2e1d004b084cc4b591c1239565c46435b278c7f76be09790d6d6eabc617e7d0f3aef11c375721b78600506d62856 + checksum: 203a3581bec5373e63d42e03f62129022f03d17390e9358a4e25fc1d44c43962ea80ab5bcbb91605e3025e22136bed059665a3b16835f66316f43ed391df9548 languageName: node linkType: hard -"@smithy/hash-stream-node@npm:^3.1.0": - version: 3.1.1 - resolution: "@smithy/hash-stream-node@npm:3.1.1" +"@smithy/hash-stream-node@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/hash-stream-node@npm:3.1.2" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 21d4d8ffca488a1aa83d97eb418197ca4b9c25329ce2d67a5978cd4b74ee7e609ebcb510fce3a271ce240b5e421073cda516e23cde7d9fedbb682ee02d7b7c9f + checksum: e5284ef06548e301aa50bd06fe06bf3e2ed11ecd57f73d2d85c98cf26119c2cc0084b5b8be49d4127cb798c6011651d5361958eb6546c19b45fd6c94ea11ef47 languageName: node linkType: hard -"@smithy/invalid-dependency@npm:^3.0.1": - version: 3.0.2 - resolution: "@smithy/invalid-dependency@npm:3.0.2" +"@smithy/invalid-dependency@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/invalid-dependency@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 21f0f2669989d9b8ffdc86e80fa8d0a39b5ada187a21c61bc4405936a31fa054a59577fa8fde4de707de559cc3e08c80aaac0205aaacf0eaf3a2ff620fa12830 + checksum: 459b4ae4e47595e8a675ff2e8bfea7f58a41f77138416ea310c89e29312e08963a701cdc354324da9dd578a7995158b4421695365070d74b0276ddff7f701bba languageName: node linkType: hard @@ -15208,89 +15466,89 @@ __metadata: languageName: node linkType: hard -"@smithy/md5-js@npm:^3.0.1": - version: 3.0.2 - resolution: "@smithy/md5-js@npm:3.0.2" +"@smithy/md5-js@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/md5-js@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: cc8857d043b53234ce280776ac7592ed6287c911d7ac45d3b9836adbf01b9e814a1f164b8a8c5b654bde14e8ce4baed17494b983d4cfee61584da623f9b794e5 + checksum: 52ef56439be4187cc65391f4252173ffad0ce5a2ce5f636d78e9cdfb517844889340156ddbdbbe86f63e7f7e0fc924fe6905749a1c833910784015133a467406 languageName: node linkType: hard -"@smithy/middleware-content-length@npm:^3.0.1": - version: 3.0.2 - resolution: "@smithy/middleware-content-length@npm:3.0.2" +"@smithy/middleware-content-length@npm:^3.0.5": + version: 3.0.5 + resolution: "@smithy/middleware-content-length@npm:3.0.5" dependencies: - "@smithy/protocol-http": ^4.0.2 - "@smithy/types": ^3.2.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 67758207c3a26eb6d44fd922d178299418fc42a07937813364a17a76547bf736df75d279cb493fca9ac5c3897c0c8d24c6e124f3edc143c991a26b44521eb423 + checksum: 21c667530f5e64db300827dfe8aa5b18396d151ac489a3e634f882179fae5c0f84940e1f831f0bf7b4b6b9623283f4a516da92d89c13ba395aede8788b523cd3 languageName: node linkType: hard -"@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" +"@smithy/middleware-endpoint@npm:^3.1.0": + version: 3.1.0 + resolution: "@smithy/middleware-endpoint@npm:3.1.0" dependencies: - "@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 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: 15a37293aa590bd0c8ab59430e967f786500603bca92dbde655480c3b7c1812a8cbcd267ff31691c2d8ea596f7917769ef91fa4033e07ec9971bf252fc12ebcd + checksum: 3271b7c1ec5d01db63439757d198e921618a2f1d4827c64fc425163e7d1bc969049d8c8ce74f3a8c0b0dac5ea3466c154f38805c8d62fe19fb9bd6af72ca2d3c 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" +"@smithy/middleware-retry@npm:^3.0.13": + version: 3.0.13 + resolution: "@smithy/middleware-retry@npm:3.0.13" 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 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/service-error-classification": ^3.0.3 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: c17ac5665e0dd2315e996c219b5aa2327c9270a49ca7dc64b8d81c80261f9d0098d3725641f2e4c87aac293c283d709fb062b5c7be6912e72f9042492a3e91d9 + checksum: 3aa98ae08633022dedc19a60b173289d4c8e04c94fe45a626499269f596de517a94b587272a578d554d1e91dc8cb19297e3d3c45da01829d520a6c730e77df36 languageName: node linkType: hard -"@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" +"@smithy/middleware-serde@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/middleware-serde@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 16c933ecb8061ff9fcf49ecabcc54b6d56de0e02464e5dd995ac729ad06e70be7a341c329b0b7cc1b33c8dbaa31372e337130e9eb6aac4c2df63ce37cb36d54f + checksum: 6c633bb8957e078d480888bd33d5a8c269a483a1358c2b28c62daecfd442c711c509d9e69302e6b19fc298139ee67cdda63a604e7da0e4ef9005117d8e0897cc languageName: node linkType: hard -"@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" +"@smithy/middleware-stack@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/middleware-stack@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 70ec59d020ae6d8c53aefecb039fb511cfa67a57ce00ba1e41d2c3da346265cc18bdf1e0724b0df10f1ef838807e151e93f6da6e886fafbac51d2ed962b795d1 + checksum: f4a450e2ebca0a8a3b4e1bbfad7d7e9c45edccbe1c984a22f2228092a526120748365e8964b478357249675d8bbc28fdaa8a4a19643a3c1d86bd74e1499327c5 languageName: node linkType: hard -"@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" +"@smithy/node-config-provider@npm:^3.1.4": + version: 3.1.4 + resolution: "@smithy/node-config-provider@npm:3.1.4" dependencies: - "@smithy/property-provider": ^3.1.2 - "@smithy/shared-ini-file-loader": ^3.1.2 - "@smithy/types": ^3.2.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 596e7a6b92fa68f6c172969bde6a04aadf35634f78a601351642b44bc271f3ad5444588a8c3dea8f7cdbe65a2d69e1c1d93291bf8d240736a035ac8db4e96ce3 + checksum: 7ea4e7cea93ab154ab89a9d6b2453c8f96b96db18883070d287bc5fa9cfd10091bb00006a15bb7e6ed25810fd1a133d458e45310a8eaa1727a55d4ce2be3ba09 languageName: node linkType: hard @@ -15307,26 +15565,26 @@ __metadata: languageName: node linkType: hard -"@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" +"@smithy/node-http-handler@npm:^3.1.4": + version: 3.1.4 + resolution: "@smithy/node-http-handler@npm:3.1.4" dependencies: - "@smithy/abort-controller": ^3.1.0 - "@smithy/protocol-http": ^4.0.2 - "@smithy/querystring-builder": ^3.0.2 - "@smithy/types": ^3.2.0 + "@smithy/abort-controller": ^3.1.1 + "@smithy/protocol-http": ^4.1.0 + "@smithy/querystring-builder": ^3.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 915cc2876cfe5b2330e868aa512930d4c126192d7695354dc2a88aab1c6639968ace36c1e8778c8a647a8b6f3f3faac2a14870607043cba972e05ee94491738a + checksum: 8f2f611bef99800b122b852103c3d1ff391b91077df191ca06676bd8c4e50d7e335bf2a311f90ff6a9fa0639a812216492e5e0ecee703e89eb05a4b253c8273c 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" +"@smithy/property-provider@npm:^3.1.3": + version: 3.1.3 + resolution: "@smithy/property-provider@npm:3.1.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 9ec0cce2728dd4a0d327fef523ca5bddcba9a7750e6e5a614293d6ba4c12d6b86c32020689481a529b4797d07315fd84647f13ea0dbe91f1da7932c954b08421 + checksum: 37a3d92267a2a32c2cc17fd1f0ab2b336f75fb7807db88f6194efede9d6a66068658a7effb7773451404fca990924393dbbf3d57e2aca67ef2e489a85666e225 languageName: node linkType: hard @@ -15340,13 +15598,13 @@ __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" +"@smithy/protocol-http@npm:^4.1.0": + version: 4.1.0 + resolution: "@smithy/protocol-http@npm:4.1.0" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: e1b419e0324f20300c490491cbc32b9d151579a6ce11f708b76ed265ef3499d404d9c0e3443692984514a0f8042b456f5c7e1a62694d42c7dc9bc64bfcff0301 + checksum: fe4f97bc35075c6e6669c12ff90a4ab3dbe620b375298795d0c1104b30d04536cf002ea81f29983895c6042c7a30eecd1d2306d3ac90bf7910ec02929233f5ad languageName: node linkType: hard @@ -15361,72 +15619,73 @@ __metadata: languageName: node linkType: hard -"@smithy/querystring-builder@npm:^3.0.2": - version: 3.0.2 - resolution: "@smithy/querystring-builder@npm:3.0.2" +"@smithy/querystring-builder@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/querystring-builder@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 "@smithy/util-uri-escape": ^3.0.0 tslib: ^2.6.2 - checksum: c6f6fc8681879daed9c85b3fd2d81cbbf553addbdc1d6ab2660687d967af40eba0112e40cf1157bdd4c42784bc22977a3da9ed9dde674b7ede5e70720a0b38af + checksum: 5c46c620d87f9b4e67b8eb543667b0160fb05bbec01d62d45adb94305369dca9e82daba47d81e840fdc399fa47f9b5930ce668d65fe83ee278a1b27d59d0b5d3 languageName: node linkType: hard -"@smithy/querystring-parser@npm:^3.0.2": - version: 3.0.2 - resolution: "@smithy/querystring-parser@npm:3.0.2" +"@smithy/querystring-parser@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/querystring-parser@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 7f18281e8d73c70dc020e1a8719a8322d88130c24e8c8cffa39ffe83e9f18d28bb9d420e6026ddb17d60ac950b0fb5b9465a4ba8493086e6186f60a9573b2ad8 + checksum: 1de11cbc4325578b243a0e3e89b46371f4705d3df41ea51b37e8efa655d3b75253180b0fca9ceed8b3955a2d458689f551cd24fd904d0f65647c62c6b08795bf languageName: node linkType: hard -"@smithy/service-error-classification@npm:^3.0.2": - version: 3.0.2 - resolution: "@smithy/service-error-classification@npm:3.0.2" +"@smithy/service-error-classification@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/service-error-classification@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 - checksum: f7cfd6438286942ec1f7f059c4bdac517c64833fcbea27198880106c7e55d0c2083f0c8e22c8fe5a68f0d86e5bd33a78f644898b48008b2f14c0c13d46f0923c + "@smithy/types": ^3.3.0 + checksum: 5bef710f5698c929c97865cba41f36b0c59100b9a1c4478a2d47caeb5e3a1a18077b870b365efaa45c94666f2075bc8978f7a6e8b964afbba3a4e490eb6c13eb languageName: node linkType: hard -"@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" +"@smithy/shared-ini-file-loader@npm:^3.1.4": + version: 3.1.4 + resolution: "@smithy/shared-ini-file-loader@npm:3.1.4" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: bbb7ceaefdcbe4e43e5a65cf424e41f6a70e44fc9b05b7f8c968bd6134253e04af4455ad0fa91fda18f55695b7992c8bfc5281aa201be2a69f7733014fd84042 + checksum: c5321635f3be34e424009fc9045454a9ceec543ec20b3b9719bf3a48bbfc03b794f4545546e9c2dcb0a987de2ca5ff8999df9bf7c166c6fc7685c1fa1f068bc1 languageName: node linkType: hard -"@smithy/signature-v4@npm:^3.1.0": - version: 3.1.1 - resolution: "@smithy/signature-v4@npm:3.1.1" +"@smithy/signature-v4@npm:^4.1.0": + version: 4.1.0 + resolution: "@smithy/signature-v4@npm:4.1.0" dependencies: "@smithy/is-array-buffer": ^3.0.0 - "@smithy/types": ^3.2.0 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 "@smithy/util-hex-encoding": ^3.0.0 - "@smithy/util-middleware": ^3.0.2 + "@smithy/util-middleware": ^3.0.3 "@smithy/util-uri-escape": ^3.0.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: f7eca9889ac4252e8fff76bf31a75bbc8afebc7ac690e3fddffadaccde64fd05305b6e22ad00f8d8da3bb3ca8739d310d6abe70350a4c12c996fb0335a8bd975 + checksum: 8c58bbc5b3f9eed092351f36dc0193ed2e43f916856dc95eadc65b42460a0c5f662016156034ef8a25419f95be8f6a15a7e85469358b77db236445919f66c77e 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" +"@smithy/smithy-client@npm:^3.1.11": + version: 3.1.11 + resolution: "@smithy/smithy-client@npm:3.1.11" 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 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/protocol-http": ^4.1.0 + "@smithy/types": ^3.3.0 + "@smithy/util-stream": ^3.1.3 tslib: ^2.6.2 - checksum: be1ce3523d5b49d1c2fb75695201dcc3748583050675efc7910b0a8bc9444c781daf435bec711166e6d2f0238ed301187283362c33aa31aefd2c21b09fb305a5 + checksum: acbbd29f45d342845eebf9086fd37cbf5abc563c60f37f787be92e4922bf09594cd882a6f9dcec85073120580c030ad14a035fd10c120733ca402938d87c143b languageName: node linkType: hard @@ -15448,23 +15707,23 @@ __metadata: languageName: node linkType: hard -"@smithy/types@npm:^3.1.0, @smithy/types@npm:^3.2.0": - version: 3.2.0 - resolution: "@smithy/types@npm:3.2.0" +"@smithy/types@npm:^3.3.0": + version: 3.3.0 + resolution: "@smithy/types@npm:3.3.0" dependencies: tslib: ^2.6.2 - checksum: f07caa63cd2f1ed9a14612a9493fcc9c0aca974593e16c1328daecc7f36af2ece5e5e79c24212966180f88a183abf078bfbcd98cf362a8d8f95f3f8642d41389 + checksum: 29bb5f83c41e32f8d4094a2aba2d3dfbd763ab5943784a700f3fa22df0dcf0ccac1b1907f7a87fbb9f6f2269fcd4750524bcb48f892249e200ffe397c0981309 languageName: node linkType: hard -"@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" +"@smithy/url-parser@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/url-parser@npm:3.0.3" dependencies: - "@smithy/querystring-parser": ^3.0.2 - "@smithy/types": ^3.2.0 + "@smithy/querystring-parser": ^3.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: a0dac1ff3eac440d3dba7f2ad80eb3cfb46cf912ceb4a533b0bd87ad5b5f1e9b641ca9a247844129c33dc2901cbe753c89185b70c6d323b781b83451a738702e + checksum: 86b4bc8e6c176b56076c30233ca4cfeb98d162fe27a348ddfda5f163ce7d173b8e684aa26202bbf4e0b5695b0ad43c0cb40170ca6793652d0ea6edb00443c036 languageName: node linkType: hard @@ -15526,42 +15785,42 @@ __metadata: 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" +"@smithy/util-defaults-mode-browser@npm:^3.0.13": + version: 3.0.13 + resolution: "@smithy/util-defaults-mode-browser@npm:3.0.13" dependencies: - "@smithy/property-provider": ^3.1.2 - "@smithy/smithy-client": ^3.1.4 - "@smithy/types": ^3.2.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 bowser: ^2.11.0 tslib: ^2.6.2 - checksum: 753e21d8b6c9cbfb874dd9468823bce7ebfa979da8972fb5c67a31333513cebe09072fcb9ae803219bf41775569c8277e49f83abd96041042d3c487d299c7a0a + checksum: 087c583d0b276df7369053b068217821c4474bf3d9de3111110ef81e8d895539f80b53a11ecaaae105ce2d24a78a52d958840b8a6c6d3e18696c45f27015a3f3 languageName: node linkType: hard -"@smithy/util-defaults-mode-node@npm:^3.0.4": - version: 3.0.6 - resolution: "@smithy/util-defaults-mode-node@npm:3.0.6" +"@smithy/util-defaults-mode-node@npm:^3.0.13": + version: 3.0.13 + resolution: "@smithy/util-defaults-mode-node@npm:3.0.13" dependencies: - "@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 + "@smithy/config-resolver": ^3.0.5 + "@smithy/credential-provider-imds": ^3.2.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/property-provider": ^3.1.3 + "@smithy/smithy-client": ^3.1.11 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: d64efd2b5bd7b4b3b1a668725d34018bd8cae00b8a59991eadabf122e590ad153be4f9beda58b063b451d9f03371575c9a8e2806bcc0b7790e63fc9d839f5c95 + checksum: a56c9f06472bb42e4180fd424ec237a6ca170eef5d487d1a3806a8845cd9c0bef37b431b22a9340afee5ae26b6bca6c11647112ef73433ba949f8c671e2b2067 languageName: node linkType: hard -"@smithy/util-endpoints@npm:^2.0.2": - version: 2.0.3 - resolution: "@smithy/util-endpoints@npm:2.0.3" +"@smithy/util-endpoints@npm:^2.0.5": + version: 2.0.5 + resolution: "@smithy/util-endpoints@npm:2.0.5" dependencies: - "@smithy/node-config-provider": ^3.1.2 - "@smithy/types": ^3.2.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: f8b77a7f68bd99b73362b29a56e35270b509f76ed82c003e82dae1468f46c2c986060aea1fcb78f3d9346830f62c1c3f3e0aa4de856b8897ba183efabc22969d + checksum: bb2a96323f52beaf2820f4e5764c865cff3ac5bca0c0df6923bb4582b0f87faf1606110cd4e36005ac43f41e9673ebdca4bbb8b913880fc2a4e0ff3301250da8 languageName: node linkType: hard @@ -15574,40 +15833,40 @@ __metadata: languageName: node linkType: hard -"@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" +"@smithy/util-middleware@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/util-middleware@npm:3.0.3" dependencies: - "@smithy/types": ^3.2.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 8a6183d3fd4a7c01787fbfd1dd901b1cdf0937f3c5e73646e8377b1e3322782e191cb7c1c9278e6c84d7462d4b0e70bcac9cfca52367728b3357914db96f90cc + checksum: f37f25d65595af5ff4c3f69fa7e66545ac1651f77979e15ffbc9047e18fc668dae90458ee76add85a49ea3729c49d317e40542d5430e81e2eafe8dcae2ddb3bc languageName: node linkType: hard -"@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" +"@smithy/util-retry@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/util-retry@npm:3.0.3" dependencies: - "@smithy/service-error-classification": ^3.0.2 - "@smithy/types": ^3.2.0 + "@smithy/service-error-classification": ^3.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 68846a52a6c71658db40f54681afad8c9bdb4687dc3c12fd13c27cf9aa3b96c57469a4d5658d4caabc9c710d95f920c0a3faafc9503fb99fb6466f51072fe852 + checksum: c760595376154be67414083aa6f76094022df72987521469b124ef3ef5848c0536757dcd2006520580380db6a4d7b597a05569470c3151f71d5e678df63f4c13 languageName: node linkType: hard -"@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" +"@smithy/util-stream@npm:^3.1.3": + version: 3.1.3 + resolution: "@smithy/util-stream@npm:3.1.3" dependencies: - "@smithy/fetch-http-handler": ^3.1.0 - "@smithy/node-http-handler": ^3.1.0 - "@smithy/types": ^3.2.0 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/types": ^3.3.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: ba4a785d30606e82cbf80e644be05fad7a1813e19226ec8893a91993e0c943bc222643ab9c70625f72ee760b4f4d1632e74af586e028e7d3dc8197b1927e580b + checksum: b663124c3b857b7744a0f2db47d091c570ff4fe4e8a8d254a7e1b8fed1d57fa4dc8fb12e496f7f607666ac5bc36d6f44a57ef3132bc882ff1d869b9bfdb5fc6e languageName: node linkType: hard @@ -15649,14 +15908,14 @@ __metadata: languageName: node linkType: hard -"@smithy/util-waiter@npm:^3.0.1": - version: 3.1.1 - resolution: "@smithy/util-waiter@npm:3.1.1" +"@smithy/util-waiter@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/util-waiter@npm:3.1.2" dependencies: - "@smithy/abort-controller": ^3.1.0 - "@smithy/types": ^3.2.0 + "@smithy/abort-controller": ^3.1.1 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: dda2666bc0c91a158fdcd04eab41f01130b5d34a9d8a86ea5ed9a8d1c87829caf381fda34a0595bf4748e99365a36842afe12fbf045f532c55f0d14f49c6a448 + checksum: 35773b1bbbb215102555a55ce4de57cbd3e38f37546ca3e6748ce3856119019a613946b399c6d97981a0bad447ce9c41f87c276325ff4c0e5a2276ee4e9e384e languageName: node linkType: hard @@ -18167,7 +18426,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: @@ -20336,7 +20595,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^1.3.7, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": +"accepts@npm:^1.3.5, accepts@npm:^1.3.7, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -20413,6 +20672,13 @@ __metadata: languageName: node linkType: hard +"adm-zip@npm:^0.5.10": + version: 0.5.14 + resolution: "adm-zip@npm:0.5.14" + checksum: 83a4bc0bdff70f3276992810db96b10ffbf3c07667a9c3395e3dc60ca40ecbb920812dde212e1e21633b1508f1ea6fc427ac451aa68ee1a597b7251b2c1fc844 + languageName: node + linkType: hard + "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -20706,7 +20972,7 @@ __metadata: languageName: node linkType: hard -"any-promise@npm:^1.0.0": +"any-promise@npm:^1.0.0, any-promise@npm:^1.1.0": version: 1.3.0 resolution: "any-promise@npm:1.3.0" checksum: 0ee8a9bdbe882c90464d75d1f55cf027f5458650c4bd1f0467e65aec38ccccda07ca5844969ee77ed46d04e7dded3eaceb027e8d32f385688523fe305fa7e1de @@ -21353,7 +21619,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.6.8, axios@npm:^1.0.0, axios@npm:^1.4.0, axios@npm:^1.6.0": +"axios@npm:1.6.8": version: 1.6.8 resolution: "axios@npm:1.6.8" dependencies: @@ -21374,6 +21640,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.0.0, axios@npm:^1.4.0, axios@npm:^1.6.0, axios@npm:^1.6.7": + version: 1.7.2 + resolution: "axios@npm:1.7.2" + dependencies: + follow-redirects: ^1.15.6 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: e457e2b0ab748504621f6fa6609074ac08c824bf0881592209dfa15098ece7e88495300e02cd22ba50b3468fd712fe687e629dcb03d6a3f6a51989727405aedf + languageName: node + linkType: hard + "axobject-query@npm:^3.2.1": version: 3.2.1 resolution: "axobject-query@npm:3.2.1" @@ -22303,6 +22580,16 @@ __metadata: languageName: node linkType: hard +"cache-content-type@npm:^1.0.0": + version: 1.0.1 + resolution: "cache-content-type@npm:1.0.1" + dependencies: + mime-types: ^2.1.18 + ylru: ^1.2.0 + checksum: 18db4d59452669ccbfd7146a1510a37eb28e9eccf18ca7a4eb603dff2edc5cccdca7498fc3042a2978f76f11151fba486eb9eb69d9afa3fb124957870aef4fd3 + languageName: node + linkType: hard + "cacheable-lookup@npm:^5.0.3": version: 5.0.3 resolution: "cacheable-lookup@npm:5.0.3" @@ -22468,6 +22755,16 @@ __metadata: languageName: node linkType: hard +"chalk@npm:3.0.0, chalk@npm:^3.0.0": + version: 3.0.0 + resolution: "chalk@npm:3.0.0" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 + languageName: node + linkType: hard + "chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -22478,16 +22775,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^3.0.0": - version: 3.0.0 - resolution: "chalk@npm:3.0.0" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 - languageName: node - linkType: hard - "chalk@npm:~5.3.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" @@ -22943,17 +23230,17 @@ __metadata: languageName: node linkType: hard -"codemirror-graphql@npm:^2.0.10": - version: 2.0.11 - resolution: "codemirror-graphql@npm:2.0.11" +"codemirror-graphql@npm:^2.0.10, codemirror-graphql@npm:^2.0.13": + version: 2.0.13 + resolution: "codemirror-graphql@npm:2.0.13" dependencies: "@types/codemirror": ^0.0.90 - graphql-language-service: 5.2.0 + graphql-language-service: 5.2.2 peerDependencies: "@codemirror/language": 6.0.0 codemirror: ^5.65.3 graphql: ^15.5.0 || ^16.0.0 - checksum: cdbeb713af63a069c5526f864edf4f71dd811437e44dba7967164ea2d380c52dfe51d3ea3fde06c94ffeb596b93af737767923d6fc434c628fa4241621684950 + checksum: 7ecb2ba2716448b3c10ccc6168dbe4c636d2d82695beea40cda6f4938b4821e9abcf6446c99412bf59558340f10b45e5b74dce5f80ae4be4409b8a6b7bfcc5ec languageName: node linkType: hard @@ -23489,7 +23776,7 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:0.5.4, content-disposition@npm:^0.5.3": +"content-disposition@npm:0.5.4, content-disposition@npm:^0.5.3, content-disposition@npm:~0.5.2": version: 0.5.4 resolution: "content-disposition@npm:0.5.4" dependencies: @@ -23498,7 +23785,7 @@ __metadata: languageName: node linkType: hard -"content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": +"content-type@npm:^1.0.4, content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 @@ -23585,6 +23872,16 @@ __metadata: languageName: node linkType: hard +"cookies@npm:~0.8.0": + version: 0.8.0 + resolution: "cookies@npm:0.8.0" + dependencies: + depd: ~2.0.0 + keygrip: ~1.1.0 + checksum: 806055a44f128705265b1bc6a853058da18bf80dea3654ad99be20985b1fa1b14f86c1eef73644aab8071241f8a78acd57202b54c4c5c70769fc694fbb9c4edc + languageName: node + linkType: hard + "copy-to-clipboard@npm:^3.2.0, copy-to-clipboard@npm:^3.3.1": version: 3.3.1 resolution: "copy-to-clipboard@npm:3.3.1" @@ -23802,6 +24099,15 @@ __metadata: languageName: node linkType: hard +"cron-parser@npm:^4.2.0": + version: 4.9.0 + resolution: "cron-parser@npm:4.9.0" + dependencies: + luxon: ^3.2.1 + checksum: 3cf248fc5cae6c19ec7124962b1cd84b76f02b9bc4f58976b3bd07624db3ef10aaf1548efcc2d2dcdab0dad4f12029d640a55ecce05ea5e1596af9db585502cf + languageName: node + linkType: hard + "cron@npm:^3.0.0": version: 3.1.7 resolution: "cron@npm:3.1.7" @@ -24411,6 +24717,13 @@ __metadata: languageName: node linkType: hard +"date-format@npm:^4.0.14": + version: 4.0.14 + resolution: "date-format@npm:4.0.14" + checksum: dfe5139df6af5759b9dd3c007b899b3f60d45a9240ffeee6314ab74e6ab52e9b519a44ccf285888bdd6b626c66ee9b4c8a523075fa1140617b5beb1cbb9b18d1 + languageName: node + linkType: hard + "dateformat@npm:^3.0.3": version: 3.0.3 resolution: "dateformat@npm:3.0.3" @@ -24434,6 +24747,13 @@ __metadata: languageName: node linkType: hard +"debounce-promise@npm:^3.1.2": + version: 3.1.2 + resolution: "debounce-promise@npm:3.1.2" + checksum: 29bac4524c423cc852319d7455363909ea3d933a3b9e3eb1149d963cffc34c475fe37219d0bafc61af566500b5d663cba579bbad7ee4023bef06f8394ed900ad + languageName: node + linkType: hard + "debounce@npm:^1.2.0": version: 1.2.1 resolution: "debounce@npm:1.2.1" @@ -24471,6 +24791,15 @@ __metadata: languageName: node linkType: hard +"debug@npm:~3.1.0": + version: 3.1.0 + resolution: "debug@npm:3.1.0" + dependencies: + ms: 2.0.0 + checksum: 0b52718ab957254a5b3ca07fc34543bc778f358620c206a08452251eb7fc193c3ea3505072acbf4350219c14e2d71ceb7bdaa0d3370aa630b50da790458d08b3 + languageName: node + linkType: hard + "debuglog@npm:^1.0.1": version: 1.0.1 resolution: "debuglog@npm:1.0.1" @@ -24540,6 +24869,13 @@ __metadata: languageName: node linkType: hard +"deep-equal@npm:~1.0.1": + version: 1.0.1 + resolution: "deep-equal@npm:1.0.1" + checksum: 5af8cbfcebf190491878a498caccc7dc9592f8ebd1685b976eacc3825619d222b5e929923163b92c4f414494e2b884f7ebf00c022e8198e8292deb70dd9785f4 + languageName: node + linkType: hard + "deep-extend@npm:0.6.0, deep-extend@npm:^0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -24746,7 +25082,7 @@ __metadata: languageName: node linkType: hard -"destroy@npm:1.2.0": +"destroy@npm:1.2.0, destroy@npm:^1.0.4": version: 1.2.0 resolution: "destroy@npm:1.2.0" checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 @@ -25412,7 +25748,7 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:~1.0.2": +"encodeurl@npm:^1.0.2, encodeurl@npm:~1.0.2": version: 1.0.2 resolution: "encodeurl@npm:1.0.2" checksum: e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c @@ -25501,6 +25837,13 @@ __metadata: languageName: node linkType: hard +"error-inject@npm:^1.0.0": + version: 1.0.0 + resolution: "error-inject@npm:1.0.0" + checksum: 258cb26c7c7e04d9b730d074926ff5e18755b6945781540fdd124cafc5015610d97e4b971eb3226469f407fd34fa899a60fbcf9ade8923ab42fa2a3c61e246cf + languageName: node + linkType: hard + "error-stack-parser@npm:^2.0.6": version: 2.0.6 resolution: "error-stack-parser@npm:2.0.6" @@ -26872,6 +27215,15 @@ __metadata: languageName: node linkType: hard +"expand-tilde@npm:^2.0.0, expand-tilde@npm:^2.0.2": + version: 2.0.2 + resolution: "expand-tilde@npm:2.0.2" + dependencies: + homedir-polyfill: ^1.0.1 + checksum: 2efe6ed407d229981b1b6ceb552438fbc9e5c7d6a6751ad6ced3e0aa5cf12f0b299da695e90d6c2ac79191b5c53c613e508f7149e4573abfbb540698ddb7301a + languageName: node + linkType: hard + "expect@npm:>28.1.3, expect@npm:^29.0.0, expect@npm:^29.7.0": version: 29.7.0 resolution: "expect@npm:29.7.0" @@ -27185,25 +27537,14 @@ __metadata: languageName: node linkType: hard -"fast-xml-parser@npm:4.2.5": - version: 4.2.5 - resolution: "fast-xml-parser@npm:4.2.5" +"fast-xml-parser@npm:4.4.1, fast-xml-parser@npm:^4.3.0, fast-xml-parser@npm:^4.3.2": + version: 4.4.1 + resolution: "fast-xml-parser@npm:4.4.1" dependencies: strnum: ^1.0.5 bin: fxparser: src/cli/cli.js - checksum: d32b22005504eeb207249bf40dc82d0994b5bb9ca9dcc731d335a1f425e47fe085b3cace3cf9d32172dd1a5544193c49e8615ca95b4bf95a4a4920a226b06d80 - languageName: node - linkType: hard - -"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: ad33a4b5165a0ffcb6e17ae78825bd4619a8298844a8a8408f2ea141a0d2d9439d18865dc5254162f09fe54d510ff18e5d5c0a190869cab21fc745ee66be816b + checksum: f440c01cd141b98789ae777503bcb6727393296094cc82924ae9f88a5b971baa4eec7e65306c7e07746534caa661fc83694ff437d9012dc84dee39dfbfaab947 languageName: node linkType: hard @@ -27411,6 +27752,15 @@ __metadata: languageName: node linkType: hard +"find-file-up@npm:^2.0.1": + version: 2.0.1 + resolution: "find-file-up@npm:2.0.1" + dependencies: + resolve-dir: ^1.0.1 + checksum: dfe820bfb80e75bed5dd5080057858c0ad2393e1438c48a3bb682663e9ecdcfbe3224ed4768bfedd00776800b4ae76bc8953d250d15ae3feabf381d2c6d04268 + languageName: node + linkType: hard + "find-my-way@npm:^4.3.3": version: 4.5.1 resolution: "find-my-way@npm:4.5.1" @@ -27423,6 +27773,15 @@ __metadata: languageName: node linkType: hard +"find-pkg@npm:2.0.0": + version: 2.0.0 + resolution: "find-pkg@npm:2.0.0" + dependencies: + find-file-up: ^2.0.1 + checksum: 44785204c8bbbdfeaece6b834ba81a35163421c30e20f531281d26e6b5890663d7ac884b82a9aebf6ce23e479336cd6f70ea5597da35495c16abdeba2fd4f845 + languageName: node + linkType: hard + "find-process@npm:^1.4.5": version: 1.4.7 resolution: "find-process@npm:1.4.7" @@ -27508,7 +27867,7 @@ __metadata: languageName: node linkType: hard -"flatted@npm:3.3.1, flatted@npm:^3.1.0": +"flatted@npm:3.3.1, flatted@npm:^3.1.0, flatted@npm:^3.2.7": version: 3.3.1 resolution: "flatted@npm:3.3.1" checksum: 85ae7181650bb728c221e7644cbc9f4bf28bc556f2fc89bb21266962bdf0ce1029cc7acc44bb646cd469d9baac7c317f64e841c4c4c00516afa97320cdac7f94 @@ -27738,7 +28097,7 @@ __metadata: languageName: node linkType: hard -"fresh@npm:0.5.2, fresh@npm:^0.5.2": +"fresh@npm:0.5.2, fresh@npm:^0.5.2, fresh@npm:~0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 @@ -27780,6 +28139,18 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:9.1.0, fs-extra@npm:^9.0.0": + version: 9.1.0 + resolution: "fs-extra@npm:9.1.0" + dependencies: + at-least-node: ^1.0.0 + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 + languageName: node + linkType: hard + "fs-extra@npm:^11.0.0, fs-extra@npm:^11.1.0, fs-extra@npm:^11.2.0": version: 11.2.0 resolution: "fs-extra@npm:11.2.0" @@ -27813,18 +28184,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^9.0.0": - version: 9.1.0 - resolution: "fs-extra@npm:9.1.0" - dependencies: - at-least-node: ^1.0.0 - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -28276,6 +28635,17 @@ __metadata: languageName: node linkType: hard +"global-modules@npm:^1.0.0": + version: 1.0.0 + resolution: "global-modules@npm:1.0.0" + dependencies: + global-prefix: ^1.0.1 + is-windows: ^1.0.1 + resolve-dir: ^1.0.0 + checksum: 10be68796c1e1abc1e2ba87ec4ea507f5629873b119ab0cd29c07284ef2b930f1402d10df01beccb7391dedd9cd479611dd6a24311c71be58937beaf18edf85e + languageName: node + linkType: hard + "global-modules@npm:^2.0.0": version: 2.0.0 resolution: "global-modules@npm:2.0.0" @@ -28285,6 +28655,19 @@ __metadata: languageName: node linkType: hard +"global-prefix@npm:^1.0.1": + version: 1.0.2 + resolution: "global-prefix@npm:1.0.2" + dependencies: + expand-tilde: ^2.0.2 + homedir-polyfill: ^1.0.1 + ini: ^1.3.4 + is-windows: ^1.0.1 + which: ^1.2.14 + checksum: 061b43470fe498271bcd514e7746e8a8535032b17ab9570517014ae27d700ff0dca749f76bbde13ba384d185be4310d8ba5712cb0e74f7d54d59390db63dd9a0 + languageName: node + linkType: hard + "global-prefix@npm:^3.0.0": version: 3.0.0 resolution: "global-prefix@npm:3.0.0" @@ -28371,9 +28754,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 @@ -28381,26 +28764,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 @@ -28538,17 +28922,18 @@ __metadata: languageName: node linkType: hard -"graphql-language-service@npm:5.2.0, graphql-language-service@npm:^5.2.0": - version: 5.2.0 - resolution: "graphql-language-service@npm:5.2.0" +"graphql-language-service@npm:5.2.2, graphql-language-service@npm:^5.2.0, graphql-language-service@npm:^5.2.2": + version: 5.2.2 + resolution: "graphql-language-service@npm:5.2.2" dependencies: + debounce-promise: ^3.1.2 nullthrows: ^1.0.0 vscode-languageserver-types: ^3.17.1 peerDependencies: graphql: ^15.5.0 || ^16.0.0 bin: graphql: dist/temp-bin.js - checksum: b053c6b7158d0ee7a3e55391bfd8be956fc5380211ca586b3a252007845e119540fb40efcc438975eaebc5ef25f46973f7ff4d9543c66e14ebd992957e0299b7 + checksum: 3f112ba67ae10096ac4a415e946cddad019ce9bd5467e29730fdfe08b4470f5b4126412edd6bfcdf6cfbd816c65e295da21134ae501e577540b319f521bc032d languageName: node linkType: hard @@ -28906,6 +29291,15 @@ __metadata: languageName: node linkType: hard +"homedir-polyfill@npm:^1.0.1": + version: 1.0.3 + resolution: "homedir-polyfill@npm:1.0.3" + dependencies: + parse-passwd: ^1.0.0 + checksum: 18dd4db87052c6a2179d1813adea0c4bfcfa4f9996f0e226fefb29eb3d548e564350fa28ec46b0bf1fbc0a1d2d6922ceceb80093115ea45ff8842a4990139250 + languageName: node + linkType: hard + "hoopy@npm:^0.1.4": version: 0.1.4 resolution: "hoopy@npm:0.1.4" @@ -29030,6 +29424,16 @@ __metadata: languageName: node linkType: hard +"http-assert@npm:^1.3.0": + version: 1.5.0 + resolution: "http-assert@npm:1.5.0" + dependencies: + deep-equal: ~1.0.1 + http-errors: ~1.8.0 + checksum: 69c9b3c14cf8b2822916360a365089ce936c883c49068f91c365eccba5c141a9964d19fdda589150a480013bf503bf37d8936c732e9635819339e730ab0e7527 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" @@ -29068,6 +29472,19 @@ __metadata: languageName: node linkType: hard +"http-errors@npm:^1.6.3, http-errors@npm:~1.8.0": + version: 1.8.1 + resolution: "http-errors@npm:1.8.1" + dependencies: + depd: ~1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: ">= 1.5.0 < 2" + toidentifier: 1.0.1 + checksum: d3c7e7e776fd51c0a812baff570bdf06fe49a5dc448b700ab6171b1250e4cf7db8b8f4c0b133e4bfe2451022a5790c1ca6c2cae4094dedd6ac8304a1267f91d2 + languageName: node + linkType: hard + "http-errors@npm:~1.6.2": version: 1.6.3 resolution: "http-errors@npm:1.6.3" @@ -29531,7 +29948,7 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.5, ini@npm:~1.3.0": +"ini@npm:^1.3.4, ini@npm:^1.3.5, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 @@ -30428,7 +30845,7 @@ __metadata: languageName: node linkType: hard -"is-windows@npm:^1.0.0, is-windows@npm:^1.0.2": +"is-windows@npm:^1.0.0, is-windows@npm:^1.0.1, is-windows@npm:^1.0.2": version: 1.0.2 resolution: "is-windows@npm:1.0.2" checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7 @@ -32000,6 +32417,15 @@ __metadata: languageName: node linkType: hard +"keygrip@npm:~1.1.0": + version: 1.1.0 + resolution: "keygrip@npm:1.1.0" + dependencies: + tsscmp: 1.0.6 + checksum: 078cd16a463d187121f0a27c1c9c95c52ad392b620f823431689f345a0501132cee60f6e96914b07d570105af470b96960402accd6c48a0b1f3cd8fac4fa2cae + languageName: node + linkType: hard + "keyv@npm:*, keyv@npm:^4.0.0, keyv@npm:^4.5.2": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -32110,6 +32536,64 @@ __metadata: languageName: node linkType: hard +"koa-compose@npm:^3.0.0": + version: 3.2.1 + resolution: "koa-compose@npm:3.2.1" + dependencies: + any-promise: ^1.1.0 + checksum: ff8e5fc0348455acf751179c6c613eb030a5fac6406d3b49ae9e00460b7ee8770db3ef62633fd3db0306cd4a6d2a0b5152399ebd5bb5e684418f9eeeb251c2de + languageName: node + linkType: hard + +"koa-compose@npm:^4.1.0": + version: 4.1.0 + resolution: "koa-compose@npm:4.1.0" + checksum: 46cb16792d96425e977c2ae4e5cb04930280740e907242ec9c25e3fb8b4a1d7b54451d7432bc24f40ec62255edea71894d2ceeb8238501842b4e48014f2e83db + languageName: node + linkType: hard + +"koa-convert@npm:^1.2.0": + version: 1.2.0 + resolution: "koa-convert@npm:1.2.0" + dependencies: + co: ^4.6.0 + koa-compose: ^3.0.0 + checksum: a33944dbda4ed87565985f5b37ba1122a012db872724b216b6fd8f9176d4bba42c4a9bf3c129330e45f6474d28f50ca0ed28d41b9bccd2ab5d36d6436cf0d676 + languageName: node + linkType: hard + +"koa@npm:2.11.0": + version: 2.11.0 + resolution: "koa@npm:2.11.0" + dependencies: + accepts: ^1.3.5 + cache-content-type: ^1.0.0 + content-disposition: ~0.5.2 + content-type: ^1.0.4 + cookies: ~0.8.0 + debug: ~3.1.0 + delegates: ^1.0.0 + depd: ^1.1.2 + destroy: ^1.0.4 + encodeurl: ^1.0.2 + error-inject: ^1.0.0 + escape-html: ^1.0.3 + fresh: ~0.5.2 + http-assert: ^1.3.0 + http-errors: ^1.6.3 + is-generator-function: ^1.0.7 + koa-compose: ^4.1.0 + koa-convert: ^1.2.0 + on-finished: ^2.3.0 + only: ~0.0.2 + parseurl: ^1.3.2 + statuses: ^1.5.0 + type-is: ^1.6.16 + vary: ^1.1.2 + checksum: b08e1aea03e70fe4ff6e35dee9f9e979e8608461ee1002f6e8dd72f45fc49404873888ea9a3aab2904e24bf43522df7c601033522f4151189e4055e87f94a979 + languageName: node + linkType: hard + "kubernetes-models@npm:^4.1.0, kubernetes-models@npm:^4.3.1": version: 4.3.1 resolution: "kubernetes-models@npm:4.3.1" @@ -32294,6 +32778,15 @@ __metadata: languageName: node linkType: hard +"linkify-it@npm:^5.0.0": + version: 5.0.0 + resolution: "linkify-it@npm:5.0.0" + dependencies: + uc.micro: ^2.0.0 + checksum: b0b86cadaf816b64c947a83994ceaad1c15f9fe7e079776ab88699fb71afd7b8fc3fd3d0ae5ebec8c92c1d347be9ba257b8aef338c0ebf81b0d27dcf429a765a + languageName: node + linkType: hard + "linkify-react@npm:4.1.3": version: 4.1.3 resolution: "linkify-react@npm:4.1.3" @@ -32456,6 +32949,13 @@ __metadata: languageName: node linkType: hard +"lodash.clonedeepwith@npm:4.5.0": + version: 4.5.0 + resolution: "lodash.clonedeepwith@npm:4.5.0" + checksum: 9fbf4ebfa04b381df226a2298eba680327bea3d0d5d19c5118de7ae218fd219186e30e9fd0d33b13729f34ffbc83c1cf09cb27aff265ba94cb602b8a2b1e71c9 + languageName: node + linkType: hard + "lodash.curry@npm:^4.0.1, lodash.curry@npm:^4.1.1": version: 4.1.1 resolution: "lodash.curry@npm:4.1.1" @@ -32700,6 +33200,19 @@ __metadata: languageName: node linkType: hard +"log4js@npm:6.9.1": + version: 6.9.1 + resolution: "log4js@npm:6.9.1" + dependencies: + date-format: ^4.0.14 + debug: ^4.3.4 + flatted: ^3.2.7 + rfdc: ^1.3.0 + streamroller: ^3.1.5 + checksum: 59d98c37d4163138dab5d9b06ae26965d1353106fece143973d57b1003b3a482791aa21374fd2cca81a953b8837b2f9756ac225404e60cbfa4dd3ab59f082e2e + languageName: node + linkType: hard + "log@npm:^6.3.1": version: 6.3.1 resolution: "log@npm:6.3.1" @@ -32736,6 +33249,13 @@ __metadata: languageName: node linkType: hard +"long-timeout@npm:0.1.1": + version: 0.1.1 + resolution: "long-timeout@npm:0.1.1" + checksum: 48668e5362cb74c4b77a6b833d59f149b9bb9e99c5a5097609807e2597cd0920613b2a42b89bd0870848298be3691064d95599a04ae010023d07dba39932afa7 + languageName: node + linkType: hard + "long@npm:^5.0.0, long@npm:^5.2.1": version: 5.2.3 resolution: "long@npm:5.2.3" @@ -32873,7 +33393,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.4.3, luxon@npm:~3.4.0": +"luxon@npm:^3.0.0, luxon@npm:^3.2.1, luxon@npm:^3.4.3, luxon@npm:~3.4.0": version: 3.4.4 resolution: "luxon@npm:3.4.4" checksum: 36c1f99c4796ee4bfddf7dc94fa87815add43ebc44c8934c924946260a58512f0fd2743a629302885df7f35ccbd2d13f178c15df046d0e3b6eb71db178f1c60c @@ -33049,6 +33569,22 @@ __metadata: languageName: node linkType: hard +"markdown-it@npm:^14.1.0": + version: 14.1.0 + resolution: "markdown-it@npm:14.1.0" + dependencies: + argparse: ^2.0.1 + entities: ^4.4.0 + linkify-it: ^5.0.0 + mdurl: ^2.0.0 + punycode.js: ^2.3.1 + uc.micro: ^2.1.0 + bin: + markdown-it: bin/markdown-it.mjs + checksum: 07296b45ebd0b13a55611a24d1b1ad002c6729ec54f558f597846994b0b7b1de79d13cd99ff3e7b6e9e027f36b63125cdcf69174da294ecabdd4e6b9fff39e5d + languageName: node + linkType: hard + "markdown-table@npm:^3.0.0": version: 3.0.1 resolution: "markdown-table@npm:3.0.1" @@ -33293,6 +33829,13 @@ __metadata: languageName: node linkType: hard +"mdurl@npm:^2.0.0": + version: 2.0.0 + resolution: "mdurl@npm:2.0.0" + checksum: 880bc289ef668df0bb34c5b2b5aaa7b6ea755052108cdaf4a5e5968ad01cf27e74927334acc9ebcc50a8628b65272ae6b1fd51fae1330c130e261c0466e1a3b2 + languageName: node + linkType: hard + "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" @@ -33819,7 +34362,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.18, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -34867,6 +35410,17 @@ __metadata: languageName: node linkType: hard +"node-schedule@npm:2.1.1": + version: 2.1.1 + resolution: "node-schedule@npm:2.1.1" + dependencies: + cron-parser: ^4.2.0 + long-timeout: 0.1.1 + sorted-array-functions: ^1.3.0 + checksum: 6a8822b16fb024277c42efe710bdb35b6f1f6ab3a2f826283640511247d693f34ebd5ddf2863cd91609e7f323574e36c81cd2084dc204fa521f931380f0f963f + languageName: node + linkType: hard + "node-stdlib-browser@npm:^1.2.0": version: 1.2.0 resolution: "node-stdlib-browser@npm:1.2.0" @@ -35376,20 +35930,20 @@ __metadata: linkType: hard "octokit@npm:^3.0.0": - version: 3.2.0 - resolution: "octokit@npm:3.2.0" + version: 3.2.1 + resolution: "octokit@npm:3.2.1" dependencies: "@octokit/app": ^14.0.2 "@octokit/core": ^5.0.0 "@octokit/oauth-app": ^6.0.0 "@octokit/plugin-paginate-graphql": ^4.0.0 - "@octokit/plugin-paginate-rest": ^9.0.0 - "@octokit/plugin-rest-endpoint-methods": ^10.0.0 + "@octokit/plugin-paginate-rest": 11.3.1 + "@octokit/plugin-rest-endpoint-methods": 13.2.2 "@octokit/plugin-retry": ^6.0.0 "@octokit/plugin-throttling": ^8.0.0 "@octokit/request-error": ^5.0.0 - "@octokit/types": ^12.0.0 - checksum: 3ec8efe02144aa6210a5c846947245cbe58d31144fa8e6a1726782001d77fcd044b7e1498a56c5e47aba44c1f5726a37c261f474cb46b816579549f7a09db1f6 + "@octokit/types": ^13.0.0 + checksum: e5608f848fb11808d0c977d946c24bffa622179daf8566c4941f6050551d368aa750b362a95aea14647facd0919e4af392c67b2409f8642dc9f27c7b6c0f964e languageName: node linkType: hard @@ -35461,6 +36015,13 @@ __metadata: languageName: node linkType: hard +"only@npm:~0.0.2": + version: 0.0.2 + resolution: "only@npm:0.0.2" + checksum: d399710db867a1ef436dd3ce74499c87ece794aa81ab0370b5d153968766ee4aed2f98d3f92fc87c963e45b7a74d400d6f463ef651a5e7cfb861b15e88e9efe6 + languageName: node + linkType: hard + "ono@npm:^7.1.3": version: 7.1.3 resolution: "ono@npm:7.1.3" @@ -35982,6 +36543,13 @@ __metadata: languageName: node linkType: hard +"parse-passwd@npm:^1.0.0": + version: 1.0.0 + resolution: "parse-passwd@npm:1.0.0" + checksum: 4e55e0231d58f828a41d0f1da2bf2ff7bcef8f4cb6146e69d16ce499190de58b06199e6bd9b17fbf0d4d8aef9052099cdf8c4f13a6294b1a522e8e958073066e + languageName: node + linkType: hard + "parse-path@npm:^7.0.0": version: 7.0.0 resolution: "parse-path@npm:7.0.0" @@ -36016,7 +36584,7 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": +"parseurl@npm:^1.3.2, parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 @@ -36661,27 +37229,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.45.0": - version: 1.45.0 - resolution: "playwright-core@npm:1.45.0" +"playwright-core@npm:1.45.3": + version: 1.45.3 + resolution: "playwright-core@npm:1.45.3" bin: playwright-core: cli.js - checksum: e81a55eeefa997fcb559527127c9cefbbabe81f196de486224e6c2a3a66852dab883379ff28a05b8008fb0ad4992840ad53c2415cee27e2d1778836210d9248e + checksum: cecb58877b2c643403d7a72c24a7aa0fdd087a3c7f9a5ea5403851336ea831d8e304b1f159aacbbabd12e5c47eaac054333746c9e5431ec07b13d64dbf3b50ec languageName: node linkType: hard -"playwright@npm:1.45.0": - version: 1.45.0 - resolution: "playwright@npm:1.45.0" +"playwright@npm:1.45.3": + version: 1.45.3 + resolution: "playwright@npm:1.45.3" dependencies: fsevents: 2.3.2 - playwright-core: 1.45.0 + playwright-core: 1.45.3 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 2a5f827fdcc90f1ec0ea4d9e4f2021ae894df88d3c0577677a81f72a09d91fb15584346e63ec2f85bfc24f872976ff2a76cee6ca7d7f29a8cc3159ced4f25b50 + checksum: d9d23b155ccd001553214f710561b01e48eb409676102f8ab94c0b4aa5ac5f398becc1a96528b0554944e07e34189503d891913e0e0a4aa58ad36b9c08747983 languageName: node linkType: hard @@ -37538,18 +38106,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 @@ -37563,27 +38131,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 @@ -37656,6 +38204,13 @@ __metadata: languageName: node linkType: hard +"punycode.js@npm:^2.3.1": + version: 2.3.1 + resolution: "punycode.js@npm:2.3.1" + checksum: 13466d7ed5e8dacdab8c4cc03837e7dd14218a59a40eb14a837f1f53ca396e18ef2c4ee6d7766b8ed2fc391d6a3ac489eebf2de83b3596f5a54e86df4a251b72 + languageName: node + linkType: hard + "punycode@npm:1.3.2": version: 1.3.2 resolution: "punycode@npm:1.3.2" @@ -37813,6 +38368,13 @@ __metadata: languageName: node linkType: hard +"rambda@npm:^9.1.0": + version: 9.2.1 + resolution: "rambda@npm:9.2.1" + checksum: d877b61f2c1e8a1878ca1e40a181702b360f6c3978bf0e55e62315a1aa215863b7ecb8f00077e2bc0f1ca0d455387fafd7a84b5c8dd004eb3cf071b15827cff7 + languageName: node + linkType: hard + "ramda-adjunct@npm:^5.0.0": version: 5.0.1 resolution: "ramda-adjunct@npm:5.0.1" @@ -39210,6 +39772,16 @@ __metadata: languageName: node linkType: hard +"resolve-dir@npm:^1.0.0, resolve-dir@npm:^1.0.1": + version: 1.0.1 + resolution: "resolve-dir@npm:1.0.1" + dependencies: + expand-tilde: ^2.0.0 + global-modules: ^1.0.0 + checksum: ef736b8ed60d6645c3b573da17d329bfb50ec4e1d6c5ffd6df49e3497acef9226f9810ea6823b8ece1560e01dcb13f77a9f6180d4f242d00cc9a8f4de909c65c + languageName: node + linkType: hard + "resolve-from@npm:5.0.0, resolve-from@npm:^5.0.0": version: 5.0.0 resolution: "resolve-from@npm:5.0.0" @@ -39238,7 +39810,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1": +"resolve@npm:1.22.8, resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -39274,7 +39846,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@^1.22.8#~builtin, resolve@patch:resolve@~1.22.1#~builtin": +"resolve@patch:resolve@1.22.8#~builtin, resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@^1.22.8#~builtin, resolve@patch:resolve@~1.22.1#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -39409,10 +39981,10 @@ __metadata: languageName: node linkType: hard -"rfdc@npm:^1.3.1": - version: 1.3.1 - resolution: "rfdc@npm:1.3.1" - checksum: d5d1e930aeac7e0e0a485f97db1356e388bdbeff34906d206fe524dd5ada76e95f186944d2e68307183fdc39a54928d4426bbb6734851692cfe9195efba58b79 +"rfdc@npm:^1.3.0, rfdc@npm:^1.3.1": + version: 1.4.1 + resolution: "rfdc@npm:1.4.1" + checksum: 3b05bd55062c1d78aaabfcea43840cdf7e12099968f368e9a4c3936beb744adb41cbdb315eac6d4d8c6623005d6f87fdf16d8a10e1ff3722e84afea7281c8d13 languageName: node linkType: hard @@ -40629,6 +41201,13 @@ __metadata: languageName: node linkType: hard +"sorted-array-functions@npm:^1.3.0": + version: 1.3.0 + resolution: "sorted-array-functions@npm:1.3.0" + checksum: 673fd39ca3b6c92644d4483eac1700bb7d7555713a536822a7522a35af559bef3e72f10d89356b75042dc394cd7c2e2ab6f40024385218ec3c85bb7335032857 + languageName: node + linkType: hard + "source-list-map@npm:^2.0.0": version: 2.0.1 resolution: "source-list-map@npm:2.0.1" @@ -40985,7 +41564,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:>= 1.4.0 < 2, statuses@npm:~1.5.0": +"statuses@npm:>= 1.4.0 < 2, statuses@npm:>= 1.5.0 < 2, statuses@npm:^1.5.0, statuses@npm:~1.5.0": version: 1.5.0 resolution: "statuses@npm:1.5.0" checksum: c469b9519de16a4bb19600205cffb39ee471a5f17b82589757ca7bd40a8d92ebb6ed9f98b5a540c5d302ccbc78f15dc03cc0280dd6e00df1335568a5d5758a5c @@ -41020,9 +41599,9 @@ __metadata: linkType: hard "stream-buffers@npm:^3.0.2": - version: 3.0.2 - resolution: "stream-buffers@npm:3.0.2" - checksum: b09fdeea606e3113ebd0e07010ed0cf038608fa396130add9e45deaff5cc3ba845dc25c31ad24f8341f85907846344cb7c85f75ea52c6572e2ac646e9b6072d0 + version: 3.0.3 + resolution: "stream-buffers@npm:3.0.3" + checksum: 3f0bdc4b1fd3ff370cef5a2103dd930b8981d42d97741eeb087a660771e27f0fc35fa8a351bb36e15bbbbce0eea00fefed60d6cdff4c6c3f527580529f183807 languageName: node linkType: hard @@ -41083,6 +41662,17 @@ __metadata: languageName: node linkType: hard +"streamroller@npm:^3.1.5": + version: 3.1.5 + resolution: "streamroller@npm:3.1.5" + dependencies: + date-format: ^4.0.14 + debug: ^4.3.4 + fs-extra: ^8.1.0 + checksum: c1df5612b785ffa4b6bbf16460590b62994c57265bc55a5166eebeeb0daf648e84bc52dc6d57e0cd4e5c7609bda93076753c63ff54589febd1e0b95590f0e443 + languageName: node + linkType: hard + "streamsearch@npm:^1.1.0": version: 1.1.0 resolution: "streamsearch@npm:1.1.0" @@ -42553,6 +43143,13 @@ __metadata: languageName: node linkType: hard +"tsscmp@npm:1.0.6": + version: 1.0.6 + resolution: "tsscmp@npm:1.0.6" + checksum: 1512384def36bccc9125cabbd4c3b0e68608d7ee08127ceaa0b84a71797263f1a01c7f82fa69be8a3bd3c1396e2965d2f7b52d581d3a5eeaf3967fbc52e3b3bf + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -42689,7 +43286,7 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^1.6.18, type-is@npm:^1.6.4, type-is@npm:~1.6.18": +"type-is@npm:^1.6.16, type-is@npm:^1.6.18, type-is@npm:^1.6.4, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" dependencies: @@ -42900,6 +43497,13 @@ __metadata: languageName: node linkType: hard +"uc.micro@npm:^2.0.0, uc.micro@npm:^2.1.0": + version: 2.1.0 + resolution: "uc.micro@npm:2.1.0" + checksum: 37197358242eb9afe367502d4638ac8c5838b78792ab218eafe48287b0ed28aaca268ec0392cc5729f6c90266744de32c06ae938549aee041fc93b0f9672d6b2 + languageName: node + linkType: hard + "uglify-js@npm:^3.1.4": version: 3.17.0 resolution: "uglify-js@npm:3.17.0" @@ -43239,7 +43843,7 @@ __metadata: languageName: node linkType: hard -"upath@npm:^2.0.1": +"upath@npm:2.0.1, upath@npm:^2.0.1": version: 2.0.1 resolution: "upath@npm:2.0.1" checksum: 2db04f24a03ef72204c7b969d6991abec9e2cb06fb4c13a1fd1c59bc33b46526b16c3325e55930a11ff86a77a8cbbcda8f6399bf914087028c5beae21ecdb33c @@ -43658,7 +44262,7 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1, vary@npm:~1.1.2": +"vary@npm:^1, vary@npm:^1.1.2, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b @@ -44245,7 +44849,7 @@ __metadata: languageName: node linkType: hard -"which@npm:^1.2.9, which@npm:^1.3.1": +"which@npm:^1.2.14, which@npm:^1.2.9, which@npm:^1.3.1": version: 1.3.1 resolution: "which@npm:1.3.1" dependencies: @@ -44425,8 +45029,8 @@ __metadata: linkType: hard "ws@npm:*, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.14.2, ws@npm:^8.16.0, ws@npm:^8.17.0, ws@npm:^8.8.0": - version: 8.17.1 - resolution: "ws@npm:8.17.1" + version: 8.18.0 + resolution: "ws@npm:8.18.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -44435,7 +45039,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 442badcce1f1178ec87a0b5372ae2e9771e07c4929a3180321901f226127f252441e8689d765aa5cfba5f50ac60dd830954afc5aeae81609aefa11d3ddf5cecf + checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 languageName: node linkType: hard @@ -44454,6 +45058,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.17.0": + version: 8.17.0 + resolution: "ws@npm:8.17.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 147ef9eab0251364e1d2c55338ad0efb15e6913923ccbfdf20f7a8a6cb8f88432bcd7f4d8f66977135bfad35575644f9983201c1a361019594a4e53977bf6d4e + languageName: node + linkType: hard + "ws@npm:^7, ws@npm:^7.4.6, ws@npm:^7.5.5": version: 7.5.10 resolution: "ws@npm:7.5.10" @@ -44733,6 +45352,7 @@ __metadata: "@yarnpkg/core": ^4.0.3 "@yarnpkg/fslib": ^3.0.2 chalk: ^4.0.0 + lodash: ^4.17.21 nodemon: ^3.0.1 semver: ^7.6.0 languageName: unknown @@ -44795,6 +45415,13 @@ __metadata: languageName: node linkType: hard +"ylru@npm:^1.2.0": + version: 1.4.0 + resolution: "ylru@npm:1.4.0" + checksum: e0bf797476487e3d57a6e8790cbb749cff2089e2afc87e46bc84ce7605c329d578ff422c8e8c2ddf167681ddd218af0f58e099733ae1044cba9e9472ebedc01d + languageName: node + linkType: hard + "yml-loader@npm:^2.1.0": version: 2.1.0 resolution: "yml-loader@npm:2.1.0"