diff --git a/.changeset/afraid-needles-divide.md b/.changeset/afraid-needles-divide.md deleted file mode 100644 index 6db7f449b0..0000000000 --- a/.changeset/afraid-needles-divide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Removed `packages/backend/src/types.ts` from the template as it is unused. It was mistakenly left in after moving the template to the new backend system. diff --git a/.changeset/beige-eagles-cheat.md b/.changeset/beige-eagles-cheat.md new file mode 100644 index 0000000000..5b5081d2ee --- /dev/null +++ b/.changeset/beige-eagles-cheat.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': patch +--- + +Updated doc link. diff --git a/.changeset/brave-apples-move.md b/.changeset/brave-apples-move.md new file mode 100644 index 0000000000..7a1fa86a56 --- /dev/null +++ b/.changeset/brave-apples-move.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Fixed a potential crash when passing an object with a `null` prototype as log meta. diff --git a/.changeset/breezy-badgers-train.md b/.changeset/breezy-badgers-train.md new file mode 100644 index 0000000000..8f747b8602 --- /dev/null +++ b/.changeset/breezy-badgers-train.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': patch +--- + +Upgraded @yarnpkg/parsers to stable 3.0 diff --git a/.changeset/bright-pumpkins-rule.md b/.changeset/bright-pumpkins-rule.md deleted file mode 100644 index 07de4f313c..0000000000 --- a/.changeset/bright-pumpkins-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Allow overriding `NotificationsPage` page properties diff --git a/.changeset/calm-cars-serve.md b/.changeset/calm-cars-serve.md new file mode 100644 index 0000000000..5df2a18cd4 --- /dev/null +++ b/.changeset/calm-cars-serve.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-tasks': patch +--- + +Marked all exports as deprecated and pointed at `@backstage/backend-plugin-api` and `@backstage/backend-defaults` diff --git a/.changeset/calm-plums-wink.md b/.changeset/calm-plums-wink.md new file mode 100644 index 0000000000..edb991f616 --- /dev/null +++ b/.changeset/calm-plums-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +mkdocs-material have updated their CSS variable template, and a few are unset in Backstage. This patch adds the missing variables to ensure coverage. diff --git a/.changeset/chatty-cycles-unite.md b/.changeset/chatty-cycles-unite.md deleted file mode 100644 index 93dffbb143..0000000000 --- a/.changeset/chatty-cycles-unite.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch -'@backstage/core-compat-api': patch -'@backstage/create-app': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-catalog': patch ---- - -Update local development dependencies. diff --git a/.changeset/chilly-adults-sing.md b/.changeset/chilly-adults-sing.md deleted file mode 100644 index 82f4cb88b2..0000000000 --- a/.changeset/chilly-adults-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Add lifecycle monitoring for the catalog processing diff --git a/.changeset/chilly-fireants-roll.md b/.changeset/chilly-fireants-roll.md deleted file mode 100644 index 93c05fecb7..0000000000 --- a/.changeset/chilly-fireants-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Use relative time when displaying visits from the same day diff --git a/.changeset/clever-radios-yawn.md b/.changeset/clever-radios-yawn.md new file mode 100644 index 0000000000..e5600183f5 --- /dev/null +++ b/.changeset/clever-radios-yawn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Make sure that the toggle button state is properly reflected in API cards diff --git a/.changeset/cold-rats-leave.md b/.changeset/cold-rats-leave.md deleted file mode 100644 index 6fe28d6371..0000000000 --- a/.changeset/cold-rats-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Fix issue with the log format not being respected when logging from actions diff --git a/.changeset/cold-seas-end.md b/.changeset/cold-seas-end.md new file mode 100644 index 0000000000..96fa048fbd --- /dev/null +++ b/.changeset/cold-seas-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Updated configuration schema to include the `useRedisSets` cache config option. diff --git a/.changeset/cool-elephants-march.md b/.changeset/cool-elephants-march.md deleted file mode 100644 index 2396f9553d..0000000000 --- a/.changeset/cool-elephants-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitea': patch ---- - -Allow defining `repoVisibility` field for the action `publish:gitea` diff --git a/.changeset/create-app-1716302437.md b/.changeset/create-app-1716302437.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1716302437.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/create-app-1716903719.md b/.changeset/create-app-1716903719.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1716903719.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/cuddly-chairs-kick.md b/.changeset/cuddly-chairs-kick.md deleted file mode 100644 index ebb53b8e26..0000000000 --- a/.changeset/cuddly-chairs-kick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Add ability to configure the Node.js HTTP Server when configuring the root HTTP Router service diff --git a/.changeset/cuddly-eggs-sin.md b/.changeset/cuddly-eggs-sin.md new file mode 100644 index 0000000000..bfe7de9680 --- /dev/null +++ b/.changeset/cuddly-eggs-sin.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-techdocs-node': patch +--- + +Allow defining custom build log transport for techdocs builder diff --git a/.changeset/curly-shirts-flow.md b/.changeset/curly-shirts-flow.md deleted file mode 100644 index b9a73809ba..0000000000 --- a/.changeset/curly-shirts-flow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Update the paths logic in the api reports command to support complex subpaths diff --git a/.changeset/curvy-planes-flash.md b/.changeset/curvy-planes-flash.md deleted file mode 100644 index 0d3368e53d..0000000000 --- a/.changeset/curvy-planes-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch ---- - -Allow skipping archived repositories (`skipArchivedRepos` flag) on Bitbucket. diff --git a/.changeset/cyan-jobs-visit.md b/.changeset/cyan-jobs-visit.md new file mode 100644 index 0000000000..ccc8c90adf --- /dev/null +++ b/.changeset/cyan-jobs-visit.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': minor +--- + +Added `TestCaches` that functions just like `TestDatabases` diff --git a/.changeset/cyan-paws-beg.md b/.changeset/cyan-paws-beg.md new file mode 100644 index 0000000000..87c2b746a4 --- /dev/null +++ b/.changeset/cyan-paws-beg.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Added handling for dry run to githubPullRequest and githubWebhook and added tests for this functionality diff --git a/.changeset/cyan-snails-peel.md b/.changeset/cyan-snails-peel.md new file mode 100644 index 0000000000..4da79258fb --- /dev/null +++ b/.changeset/cyan-snails-peel.md @@ -0,0 +1,12 @@ +--- +'@backstage/plugin-user-settings-backend': patch +'@backstage/plugin-devtools-backend': patch +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-search-backend': patch +'@backstage/plugin-proxy-backend': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-app-backend': patch +--- + +Updated local development setup. diff --git a/.changeset/dry-sloths-impress.md b/.changeset/dry-sloths-impress.md deleted file mode 100644 index 6bd5ba4156..0000000000 --- a/.changeset/dry-sloths-impress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-model': minor ---- - -Introduce a domain attribute to the domain entity to allow a hierarchy of domains to exist. diff --git a/.changeset/eighty-apricots-kneel.md b/.changeset/eighty-apricots-kneel.md deleted file mode 100644 index a9cabaf378..0000000000 --- a/.changeset/eighty-apricots-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@techdocs/cli': patch ---- - -Fix cookie endpoint mock for `serve` diff --git a/.changeset/eighty-bats-stare.md b/.changeset/eighty-bats-stare.md deleted file mode 100644 index 6ebb2e9265..0000000000 --- a/.changeset/eighty-bats-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Update path in Readme for Plugin Techdocs to show the correct setup information. diff --git a/.changeset/eighty-kings-dress.md b/.changeset/eighty-kings-dress.md new file mode 100644 index 0000000000..52aab627ab --- /dev/null +++ b/.changeset/eighty-kings-dress.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +In preparation to the new backend system stable release, the `isDatabaseConflictError` helper have been moved to the `@backstage/backend-plugin-api` package and deprecated from `@backstage/backend-common`. diff --git a/.changeset/eighty-yaks-switch.md b/.changeset/eighty-yaks-switch.md new file mode 100644 index 0000000000..30e3374d70 --- /dev/null +++ b/.changeset/eighty-yaks-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix readme for new plugins created using cli diff --git a/.changeset/eleven-pandas-divide.md b/.changeset/eleven-pandas-divide.md deleted file mode 100644 index 912d34570a..0000000000 --- a/.changeset/eleven-pandas-divide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -Added events support for `GitlabDiscoveryEntityProvider` and `GitlabOrgDiscoveryEntityProvider`. diff --git a/.changeset/empty-spoons-tell.md b/.changeset/empty-spoons-tell.md new file mode 100644 index 0000000000..44e3dceb6f --- /dev/null +++ b/.changeset/empty-spoons-tell.md @@ -0,0 +1,46 @@ +--- +'@backstage/plugin-proxy-backend': minor +--- + +**BREAKING**: The proxy backend plugin is now protected by Backstage auth, by +default. Unless specifically configured (see below), all proxy endpoints will +reject requests immediately unless a valid Backstage user or service token is +passed along with the request. This aligns the proxy with how other Backstage +backends behave out of the box, and serves to protect your upstreams from +unauthorized access. + +A proxy configuration section can now look as follows: + +```yaml +proxy: + endpoints: + '/pagerduty': + target: https://api.pagerduty.com + credentials: require # NEW! + headers: + Authorization: Token token=${PAGERDUTY_TOKEN} +``` + +There are three possible `credentials` settings at this point: + +- `require`: Callers must provide Backstage user or service credentials with + each request. The credentials are not forwarded to the proxy target. +- `forward`: Callers must provide Backstage user or service credentials with + each request, and those credentials are forwarded to the proxy target. +- `dangerously-allow-unauthenticated`: No Backstage credentials are required to + access this proxy target. The target can still apply its own credentials + checks, but the proxy will not help block non-Backstage-blessed callers. If + you also add `allowedHeaders: ['Authorization']` to an endpoint configuration, + then the Backstage token (if provided) WILL be forwarded. + +The value `dangerously-allow-unauthenticated` was the old default. + +The value `require` is the new default, so requests that were previously +permitted may now start resulting in `401 Unauthorized` responses. If you have +`backend.auth.dangerouslyDisableDefaultAuthPolicy` set to `true`, this does not +apply; the proxy will behave as if all endpoints were set to +`dangerously-allow-unauthenticated`. + +If you have proxy endpoints that require unauthenticated access still, please +add `credentials: dangerously-allow-unauthenticated` to their declarations in +your app-config. diff --git a/.changeset/empty-tables-ring.md b/.changeset/empty-tables-ring.md new file mode 100644 index 0000000000..c83a987228 --- /dev/null +++ b/.changeset/empty-tables-ring.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-kubernetes-react': minor +'@backstage/plugin-catalog-import': minor +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-search': patch +--- + +Migrate from identityApi to fetchApi in frontend plugins. diff --git a/.changeset/famous-monkeys-count.md b/.changeset/famous-monkeys-count.md new file mode 100644 index 0000000000..c5151b38c3 --- /dev/null +++ b/.changeset/famous-monkeys-count.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Add support for JWKS tokens in ExternalTokenHandler. diff --git a/.changeset/fix-stackoverflow.md b/.changeset/fix-stackoverflow.md deleted file mode 100644 index 6ce9f15737..0000000000 --- a/.changeset/fix-stackoverflow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch ---- - -Fix plugin/incremental-ingestion 'Maximum call stack size exceeded' error when ingest large entities. diff --git a/.changeset/fluffy-hotels-wait.md b/.changeset/fluffy-hotels-wait.md deleted file mode 100644 index a578f2fb4a..0000000000 --- a/.changeset/fluffy-hotels-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Both the target and types library have been bumped from ES2021 to ES2022 in `@backstage/cli/config/tsconfig.json`. diff --git a/.changeset/forty-adults-roll.md b/.changeset/forty-adults-roll.md new file mode 100644 index 0000000000..50dd60da9e --- /dev/null +++ b/.changeset/forty-adults-roll.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-tasks': patch +--- + +Updated the `TaskScheduleDefinitionConfig` deprecated comment to point to `SchedulerServiceTaskScheduleDefinitionConfig` diff --git a/.changeset/four-adults-mix.md b/.changeset/four-adults-mix.md new file mode 100644 index 0000000000..5013166dc6 --- /dev/null +++ b/.changeset/four-adults-mix.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications': patch +--- + +Do not always show scrollbars in notification description diff --git a/.changeset/four-cooks-serve.md b/.changeset/four-cooks-serve.md deleted file mode 100644 index 864807cc49..0000000000 --- a/.changeset/four-cooks-serve.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-notifications-backend': patch -'@backstage/plugin-notifications-node': patch ---- - -Support for filtering entities from notification recipients after resolving them from the recipients diff --git a/.changeset/fresh-crews-impress.md b/.changeset/fresh-crews-impress.md deleted file mode 100644 index 18f98f1dd9..0000000000 --- a/.changeset/fresh-crews-impress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Move the JWKS registration outside of the lifecycle middleware diff --git a/.changeset/friendly-keys-fold.md b/.changeset/friendly-keys-fold.md new file mode 100644 index 0000000000..218abe4efe --- /dev/null +++ b/.changeset/friendly-keys-fold.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/backend-app-api': patch +--- + +Added an optional `accessRestrictions` to external access service tokens and service principals in general, such that you can limit their access to certain plugins or permissions. diff --git a/.changeset/fuzzy-seahorses-tell.md b/.changeset/fuzzy-seahorses-tell.md deleted file mode 100644 index f184e9ce95..0000000000 --- a/.changeset/fuzzy-seahorses-tell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed an internal circular import that broke Jest mocks. diff --git a/.changeset/gentle-baboons-peel.md b/.changeset/gentle-baboons-peel.md new file mode 100644 index 0000000000..b51ad77283 --- /dev/null +++ b/.changeset/gentle-baboons-peel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +`TechDocsIndexPage` now accepts an optional `ownerPickerMode` for toggling the behavior of the `EntityOwnerPicker`, exposing a new mode `` particularly suitable for larger catalogs. In this new mode, `EntityOwnerPicker` will display all the users and groups present in the catalog. diff --git a/.changeset/gold-teachers-wink.md b/.changeset/gold-teachers-wink.md new file mode 100644 index 0000000000..0578e8d02b --- /dev/null +++ b/.changeset/gold-teachers-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix issue with `esm` loaded dependencies being different from the `cjs` import for Vite dependencies diff --git a/.changeset/gold-waves-bake.md b/.changeset/gold-waves-bake.md deleted file mode 100644 index 2883b7b967..0000000000 --- a/.changeset/gold-waves-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add support for `versions:migrate` to do code changes. Can be skipped with `--no-code-changes` diff --git a/.changeset/gorgeous-cameras-cross.md b/.changeset/gorgeous-cameras-cross.md deleted file mode 100644 index 50d7ddb2d7..0000000000 --- a/.changeset/gorgeous-cameras-cross.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-addons-test-utils': patch ---- - -Fix bug in TechDocsAddonTester when jest.resetAllMocks is called between tests diff --git a/.changeset/great-cougars-guess.md b/.changeset/great-cougars-guess.md new file mode 100644 index 0000000000..af1de3e8ce --- /dev/null +++ b/.changeset/great-cougars-guess.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Made it possible to give access restrictions to `mockCredentials.service` diff --git a/.changeset/green-adults-push.md b/.changeset/green-adults-push.md deleted file mode 100644 index 3edc21c385..0000000000 --- a/.changeset/green-adults-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add preserveModules to rollup, which allows better async loading and tree-shaking in webpack diff --git a/.changeset/green-boxes-rescue.md b/.changeset/green-boxes-rescue.md deleted file mode 100644 index 146695a320..0000000000 --- a/.changeset/green-boxes-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications-backend-module-email': patch ---- - -Allow sending notifications by email with the new notifications module diff --git a/.changeset/hip-carrots-drive.md b/.changeset/hip-carrots-drive.md deleted file mode 100644 index 5852916b74..0000000000 --- a/.changeset/hip-carrots-drive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -The default `TokenManager` implementation no longer requires keys to be configured in production, but it will throw an errors when generating or authenticating tokens. The default `AuthService` implementation will now also provide additional context if such an error is throw when falling back to using the `TokenManager` service to generate tokens for outgoing requests. diff --git a/.changeset/hot-forks-train.md b/.changeset/hot-forks-train.md deleted file mode 100644 index a5300085b6..0000000000 --- a/.changeset/hot-forks-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Allow showing notifications as snackbars in the UI diff --git a/.changeset/itchy-gorillas-hope.md b/.changeset/itchy-gorillas-hope.md deleted file mode 100644 index cd285161ff..0000000000 --- a/.changeset/itchy-gorillas-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Removed the Tech Radar and GitHub Actions plugins from the template, which have been moved to the community plugins repository. diff --git a/.changeset/itchy-spoons-cry.md b/.changeset/itchy-spoons-cry.md new file mode 100644 index 0000000000..20877e8087 --- /dev/null +++ b/.changeset/itchy-spoons-cry.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-app-backend': patch +--- + +Restore the support of external config schema in the router of the `app-backend` plugin, which was broken in release `1.26.0`. +This support is critical for dynamic frontend plugins to have access to their config values. diff --git a/.changeset/large-months-decide.md b/.changeset/large-months-decide.md new file mode 100644 index 0000000000..e9d4c47bbe --- /dev/null +++ b/.changeset/large-months-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications-node': minor +--- + +add notifications filtering by processors diff --git a/.changeset/late-ants-impress.md b/.changeset/late-ants-impress.md new file mode 100644 index 0000000000..44b2cbefb3 --- /dev/null +++ b/.changeset/late-ants-impress.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +'@backstage/plugin-scaffolder-node-test-utils': patch +'@backstage/plugin-search-backend-module-elasticsearch': patch +'@backstage/plugin-search-backend-module-pg': patch +'@backstage/plugin-search-backend-node': patch +'@backstage/plugin-signals-backend': patch +'@backstage/plugin-events-node': patch +--- + +Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. diff --git a/.changeset/late-planes-fix.md b/.changeset/late-planes-fix.md deleted file mode 100644 index a57d7ec1d4..0000000000 --- a/.changeset/late-planes-fix.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-search-backend-node': patch -'@backstage/plugin-search-backend': patch ---- - -Add lifecycle monitoring for the search index registry diff --git a/.changeset/late-students-live.md b/.changeset/late-students-live.md new file mode 100644 index 0000000000..6a7c203e9e --- /dev/null +++ b/.changeset/late-students-live.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Fixed bug in CopyToClipboardButton component where positioning of the "Copy to clipboard" button in techdocs code snippets was broken in some cases diff --git a/.changeset/light-rice-argue.md b/.changeset/light-rice-argue.md new file mode 100644 index 0000000000..23572b4cdd --- /dev/null +++ b/.changeset/light-rice-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Added `gitlab:issue:edit` action to edit existing GitLab issues diff --git a/.changeset/little-cooks-approve.md b/.changeset/little-cooks-approve.md new file mode 100644 index 0000000000..d4088208ae --- /dev/null +++ b/.changeset/little-cooks-approve.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications': patch +--- + +Fixes performance issue with Notifications title counter. diff --git a/.changeset/loud-frogs-eat.md b/.changeset/loud-frogs-eat.md deleted file mode 100644 index dd1ab978f1..0000000000 --- a/.changeset/loud-frogs-eat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Add examples for `gitlab:repo:push` scaffolder action & improve related tests diff --git a/.changeset/loud-pumpkins-bow.md b/.changeset/loud-pumpkins-bow.md new file mode 100644 index 0000000000..a55c97e19a --- /dev/null +++ b/.changeset/loud-pumpkins-bow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Links that are rendered in the markdown in the `ScaffolderField` component are now opened in new tabs. diff --git a/.changeset/loud-vans-greet.md b/.changeset/loud-vans-greet.md deleted file mode 100644 index 732413174b..0000000000 --- a/.changeset/loud-vans-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Internal refactor to only create one external token handler diff --git a/.changeset/lovely-games-cry.md b/.changeset/lovely-games-cry.md deleted file mode 100644 index 5209b93496..0000000000 --- a/.changeset/lovely-games-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-react': patch ---- - -When using `CookieAuthRefreshProvider` or `useCookieAuthRefresh`, a 404 response from the cookie endpoint will now be treated as if cookie auth is disabled and is not needed. diff --git a/.changeset/lovely-hats-pay.md b/.changeset/lovely-hats-pay.md new file mode 100644 index 0000000000..117f50e5db --- /dev/null +++ b/.changeset/lovely-hats-pay.md @@ -0,0 +1,5 @@ +--- +'@backstage/theme': patch +--- + +Internal refactor to fix an issue where the MUI 5 `v5-` class prefixing gets removed by tree shaking. diff --git a/.changeset/lucky-news-guess.md b/.changeset/lucky-news-guess.md deleted file mode 100644 index 9c2cc4e8b0..0000000000 --- a/.changeset/lucky-news-guess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch ---- - -Add examples for `publish:bitbucketServer:pull-request` scaffolder action & improve related tests diff --git a/.changeset/lucky-taxis-rule.md b/.changeset/lucky-taxis-rule.md new file mode 100644 index 0000000000..eacbaaefbe --- /dev/null +++ b/.changeset/lucky-taxis-rule.md @@ -0,0 +1,9 @@ +--- +'@backstage/backend-defaults': patch +--- + +Added core service factories and implementations from +`@backstage/backend-app-api`. They are now available as subpath exports, e.g. +`@backstage/backend-defaults/scheduler` is where the service factory and default +implementation of `coreServices.scheduler` now lives. They have been marked as +deprecated in their old locations. diff --git a/.changeset/many-moles-sing.md b/.changeset/many-moles-sing.md new file mode 100644 index 0000000000..8b49f674c7 --- /dev/null +++ b/.changeset/many-moles-sing.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +We are deprecating the legacy `createServiceBuilder` factory, so if you are still using it, please checkout the migration guide and [migrate](https://backstage.io/docs/backend-system/building-plugins-and-modules/migrating) your plugin to use the new backend system. diff --git a/.changeset/many-windows-attack.md b/.changeset/many-windows-attack.md new file mode 100644 index 0000000000..d0516244f4 --- /dev/null +++ b/.changeset/many-windows-attack.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +--- + +Remove debug console logging statement diff --git a/.changeset/mean-laws-lay.md b/.changeset/mean-laws-lay.md new file mode 100644 index 0000000000..a7c629a9a5 --- /dev/null +++ b/.changeset/mean-laws-lay.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Pass through `EventsService` too in the new backend system diff --git a/.changeset/neat-rivers-share.md b/.changeset/neat-rivers-share.md new file mode 100644 index 0000000000..42649de977 --- /dev/null +++ b/.changeset/neat-rivers-share.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': patch +--- + +Ensure that service token access restrictions, when present, are taken into account diff --git a/.changeset/nervous-queens-fly.md b/.changeset/nervous-queens-fly.md new file mode 100644 index 0000000000..802034765c --- /dev/null +++ b/.changeset/nervous-queens-fly.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Refactored `TestDatabases` to no longer depend on `backend-common` diff --git a/.changeset/new-numbers-hug.md b/.changeset/new-numbers-hug.md new file mode 100644 index 0000000000..e4e35a2825 --- /dev/null +++ b/.changeset/new-numbers-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +Moved the declaration of the `SchedulerService` here, along with prefixed versions of all of the types it depends on, from `@backstage/backend-tasks` diff --git a/.changeset/nice-pants-shave.md b/.changeset/nice-pants-shave.md new file mode 100644 index 0000000000..500888a817 --- /dev/null +++ b/.changeset/nice-pants-shave.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch +'@backstage/plugin-scaffolder-backend-module-sentry': patch +'@backstage/plugin-scaffolder-backend-module-gitea': patch +'@backstage/plugin-notifications-node': patch +--- + +Use `node-fetch` instead of native fetch, as per https://backstage.io/docs/architecture-decisions/adrs-adr013 diff --git a/.changeset/nine-hairs-kick.md b/.changeset/nine-hairs-kick.md new file mode 100644 index 0000000000..e4160640b4 --- /dev/null +++ b/.changeset/nine-hairs-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Fixed an issue in `GitlabOrgDiscoveryEntityProvider` where a missing `orgEnabled` config key was throwing an error. diff --git a/.changeset/itchy-keys-wonder.md b/.changeset/nine-ties-type.md similarity index 59% rename from .changeset/itchy-keys-wonder.md rename to .changeset/nine-ties-type.md index 879dc096a4..abb0661724 100644 --- a/.changeset/itchy-keys-wonder.md +++ b/.changeset/nine-ties-type.md @@ -3,4 +3,4 @@ '@backstage/backend-app-api': patch --- -Redact `meta` fields too with the logger +Fixing issue with log meta fields possibly being circular refs diff --git a/.changeset/old-trees-check.md b/.changeset/old-trees-check.md new file mode 100644 index 0000000000..b4d745ffb5 --- /dev/null +++ b/.changeset/old-trees-check.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-tasks': patch +--- + +Deprecate the legacy `TaskScheduler.fromConfig` method and stop using the `getVoidlogger` in tests files to reduce the dependency on the soon-to-deprecate `backstage-common` package. diff --git a/.changeset/olive-mangos-tickle.md b/.changeset/olive-mangos-tickle.md new file mode 100644 index 0000000000..6033ec3ed6 --- /dev/null +++ b/.changeset/olive-mangos-tickle.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Stop using `getVoidLogger` in tests to reduce the dependency on the soon-to-deprecate `backstage-common` package. diff --git a/.changeset/orange-numbers-think.md b/.changeset/orange-numbers-think.md deleted file mode 100644 index 21dc7ce76b..0000000000 --- a/.changeset/orange-numbers-think.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-catalog': patch ---- - -Fix wiring of the module exported at the `/alpha` path, which was causing authentication failures. diff --git a/.changeset/perfect-bikes-invite.md b/.changeset/perfect-bikes-invite.md new file mode 100644 index 0000000000..96a4ad5659 --- /dev/null +++ b/.changeset/perfect-bikes-invite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Fixed an issue in `GitlabDiscoveryEntityProvider` where the fallback branch was taking precedence over the GitLab default branch. diff --git a/.changeset/perfect-points-hope.md b/.changeset/perfect-points-hope.md deleted file mode 100644 index cfc42f77a3..0000000000 --- a/.changeset/perfect-points-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-oidc-provider': patch ---- - -Add nonce to authorize request to be added in ID token diff --git a/.changeset/polite-otters-talk.md b/.changeset/polite-otters-talk.md new file mode 100644 index 0000000000..e56b935c1e --- /dev/null +++ b/.changeset/polite-otters-talk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications-backend-module-email': minor +--- + +add notification filters diff --git a/.changeset/pre.json b/.changeset/pre.json index 809cd51567..bbf21bc6a4 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,336 +2,253 @@ "mode": "pre", "tag": "next", "initialVersions": { - "example-app": "0.2.96", - "@backstage/app-defaults": "1.5.4", - "example-app-next": "0.0.10", - "app-next-example-plugin": "0.0.10", - "example-backend": "0.2.97", - "@backstage/backend-app-api": "0.7.0", - "@backstage/backend-common": "0.21.7", - "@backstage/backend-defaults": "0.2.17", + "example-app": "0.2.97", + "@backstage/app-defaults": "1.5.5", + "example-app-next": "0.0.11", + "app-next-example-plugin": "0.0.11", + "example-backend": "0.0.26", + "@backstage/backend-app-api": "0.7.3", + "@backstage/backend-common": "0.22.0", + "@backstage/backend-defaults": "0.2.18", "@backstage/backend-dev-utils": "0.1.4", - "@backstage/backend-dynamic-feature-service": "0.2.9", - "example-backend-next": "0.0.25", - "@backstage/backend-openapi-utils": "0.1.10", - "@backstage/backend-plugin-api": "0.6.17", - "@backstage/backend-tasks": "0.5.22", - "@backstage/backend-test-utils": "0.3.7", - "@backstage/catalog-client": "1.6.4", - "@backstage/catalog-model": "1.4.5", - "@backstage/cli": "0.26.3", + "@backstage/backend-dynamic-feature-service": "0.2.10", + "example-backend-legacy": "0.2.98", + "@backstage/backend-openapi-utils": "0.1.11", + "@backstage/backend-plugin-api": "0.6.18", + "@backstage/backend-tasks": "0.5.23", + "@backstage/backend-test-utils": "0.3.8", + "@backstage/catalog-client": "1.6.5", + "@backstage/catalog-model": "1.5.0", + "@backstage/cli": "0.26.5", "@backstage/cli-common": "0.1.13", "@backstage/cli-node": "0.2.5", "@backstage/codemods": "0.1.48", "@backstage/config": "1.2.0", "@backstage/config-loader": "1.8.0", - "@backstage/core-app-api": "1.12.4", - "@backstage/core-compat-api": "0.2.4", - "@backstage/core-components": "0.14.4", + "@backstage/core-app-api": "1.12.5", + "@backstage/core-compat-api": "0.2.5", + "@backstage/core-components": "0.14.7", "@backstage/core-plugin-api": "1.9.2", - "@backstage/create-app": "0.5.14", - "@backstage/dev-utils": "1.0.31", - "e2e-test": "0.2.15", + "@backstage/create-app": "0.5.15", + "@backstage/dev-utils": "1.0.32", + "e2e-test": "0.2.16", "@backstage/e2e-test-utils": "0.1.1", "@backstage/errors": "1.2.4", - "@backstage/eslint-plugin": "0.1.7", - "@backstage/frontend-app-api": "0.6.4", - "@backstage/frontend-plugin-api": "0.6.4", - "@backstage/frontend-test-utils": "0.1.6", - "@backstage/integration": "1.10.0", + "@backstage/eslint-plugin": "0.1.8", + "@backstage/frontend-app-api": "0.7.0", + "@backstage/frontend-plugin-api": "0.6.5", + "@backstage/frontend-test-utils": "0.1.7", + "@backstage/integration": "1.11.0", "@backstage/integration-aws-node": "0.1.12", - "@backstage/integration-react": "1.1.26", + "@backstage/integration-react": "1.1.27", "@backstage/release-manifests": "0.0.11", - "@backstage/repo-tools": "0.8.0", - "@techdocs/cli": "1.8.9", - "techdocs-cli-embedded-app": "0.2.95", - "@backstage/test-utils": "1.5.4", - "@backstage/theme": "0.5.3", + "@backstage/repo-tools": "0.9.0", + "@techdocs/cli": "1.8.11", + "techdocs-cli-embedded-app": "0.2.96", + "@backstage/test-utils": "1.5.5", + "@backstage/theme": "0.5.4", "@backstage/types": "1.1.1", "@backstage/version-bridge": "1.0.8", - "@backstage/plugin-adr": "0.6.17", - "@backstage/plugin-adr-backend": "0.4.14", - "@backstage/plugin-adr-common": "0.2.22", - "@backstage/plugin-airbrake": "0.3.34", - "@backstage/plugin-airbrake-backend": "0.3.14", - "@backstage/plugin-allure": "0.1.50", - "@backstage/plugin-analytics-module-ga": "0.2.4", - "@backstage/plugin-analytics-module-ga4": "0.2.4", - "@backstage/plugin-analytics-module-newrelic-browser": "0.1.4", - "@backstage/plugin-apache-airflow": "0.2.24", - "@backstage/plugin-api-docs": "0.11.4", + "@backstage/plugin-api-docs": "0.11.5", "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.6", - "@backstage/plugin-apollo-explorer": "0.2.0", - "@backstage/plugin-app-backend": "0.3.65", - "@backstage/plugin-app-node": "0.1.17", - "@backstage/plugin-app-visualizer": "0.1.5", - "@backstage/plugin-auth-backend": "0.22.4", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.1.9", - "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.1.9", - "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.12", - "@backstage/plugin-auth-backend-module-github-provider": "0.1.14", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.14", - "@backstage/plugin-auth-backend-module-google-provider": "0.1.14", - "@backstage/plugin-auth-backend-module-guest-provider": "0.1.3", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.12", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.14", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.10", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.1.8", - "@backstage/plugin-auth-backend-module-okta-provider": "0.0.10", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.11", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.1.9", - "@backstage/plugin-auth-node": "0.4.12", - "@backstage/plugin-auth-react": "0.1.0", - "@backstage/plugin-azure-devops": "0.4.3", - "@backstage/plugin-azure-devops-backend": "0.6.4", - "@backstage/plugin-azure-devops-common": "0.4.1", - "@backstage/plugin-azure-sites": "0.1.23", - "@backstage/plugin-azure-sites-backend": "0.3.4", - "@backstage/plugin-azure-sites-common": "0.1.3", - "@backstage/plugin-badges": "0.2.58", - "@backstage/plugin-badges-backend": "0.4.0", - "@backstage/plugin-bazaar": "0.2.26", - "@backstage/plugin-bazaar-backend": "0.3.15", - "@backstage/plugin-bitbucket-cloud-common": "0.2.18", - "@backstage/plugin-bitrise": "0.1.61", - "@backstage/plugin-catalog": "1.19.0", - "@backstage/plugin-catalog-backend": "1.21.1", - "@backstage/plugin-catalog-backend-module-aws": "0.3.12", - "@backstage/plugin-catalog-backend-module-azure": "0.1.37", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.2.0", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.2.4", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.31", - "@backstage/plugin-catalog-backend-module-gcp": "0.1.18", - "@backstage/plugin-catalog-backend-module-gerrit": "0.1.34", - "@backstage/plugin-catalog-backend-module-github": "0.6.0", - "@backstage/plugin-catalog-backend-module-github-org": "0.1.12", - "@backstage/plugin-catalog-backend-module-gitlab": "0.3.15", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.22", - "@backstage/plugin-catalog-backend-module-ldap": "0.5.33", - "@backstage/plugin-catalog-backend-module-msgraph": "0.5.25", - "@backstage/plugin-catalog-backend-module-openapi": "0.1.35", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.23", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.15", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.4.4", - "@backstage/plugin-catalog-common": "1.0.22", - "@backstage/plugin-catalog-graph": "0.4.4", - "@backstage/plugin-catalog-import": "0.10.10", - "@backstage/plugin-catalog-node": "1.11.1", - "@backstage/plugin-catalog-react": "1.11.3", - "@backstage/plugin-catalog-unprocessed-entities": "0.2.3", + "@backstage/plugin-app-backend": "0.3.66", + "@backstage/plugin-app-node": "0.1.18", + "@backstage/plugin-app-visualizer": "0.1.6", + "@backstage/plugin-auth-backend": "0.22.5", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.1.10", + "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.1.10", + "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.1.1", + "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.1.1", + "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.1.1", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.13", + "@backstage/plugin-auth-backend-module-github-provider": "0.1.15", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.15", + "@backstage/plugin-auth-backend-module-google-provider": "0.1.15", + "@backstage/plugin-auth-backend-module-guest-provider": "0.1.4", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.13", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.15", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.11", + "@backstage/plugin-auth-backend-module-oidc-provider": "0.1.9", + "@backstage/plugin-auth-backend-module-okta-provider": "0.0.11", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.12", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.1.10", + "@backstage/plugin-auth-node": "0.4.13", + "@backstage/plugin-auth-react": "0.1.2", + "@backstage/plugin-bitbucket-cloud-common": "0.2.19", + "@backstage/plugin-catalog": "1.20.0", + "@backstage/plugin-catalog-backend": "1.22.0", + "@backstage/plugin-catalog-backend-module-aws": "0.3.13", + "@backstage/plugin-catalog-backend-module-azure": "0.1.38", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.2.1", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.2.5", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.32", + "@backstage/plugin-catalog-backend-module-gcp": "0.1.19", + "@backstage/plugin-catalog-backend-module-gerrit": "0.1.35", + "@backstage/plugin-catalog-backend-module-github": "0.6.1", + "@backstage/plugin-catalog-backend-module-github-org": "0.1.13", + "@backstage/plugin-catalog-backend-module-gitlab": "0.3.16", + "@backstage/plugin-catalog-backend-module-gitlab-org": "0.0.1", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.23", + "@backstage/plugin-catalog-backend-module-ldap": "0.5.34", + "@backstage/plugin-catalog-backend-module-msgraph": "0.5.26", + "@backstage/plugin-catalog-backend-module-openapi": "0.1.36", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.24", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.16", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.4.5", + "@backstage/plugin-catalog-common": "1.0.23", + "@backstage/plugin-catalog-graph": "0.4.5", + "@backstage/plugin-catalog-import": "0.11.0", + "@backstage/plugin-catalog-node": "1.12.0", + "@backstage/plugin-catalog-react": "1.12.0", + "@backstage/plugin-catalog-unprocessed-entities": "0.2.4", "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.1", - "@backstage/plugin-cicd-statistics": "0.1.36", - "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.30", - "@backstage/plugin-circleci": "0.3.34", - "@backstage/plugin-cloudbuild": "0.5.1", - "@backstage/plugin-code-climate": "0.1.34", - "@backstage/plugin-code-coverage": "0.2.27", - "@backstage/plugin-code-coverage-backend": "0.2.31", - "@backstage/plugin-codescene": "0.1.26", - "@backstage/plugin-config-schema": "0.1.54", - "@backstage/plugin-cost-insights": "0.12.23", - "@backstage/plugin-cost-insights-common": "0.1.2", - "@backstage/plugin-devtools": "0.1.13", - "@backstage/plugin-devtools-backend": "0.3.3", + "@backstage/plugin-config-schema": "0.1.55", + "@backstage/plugin-devtools": "0.1.14", + "@backstage/plugin-devtools-backend": "0.3.4", "@backstage/plugin-devtools-common": "0.1.9", - "@backstage/plugin-dynatrace": "10.0.3", - "@backstage/plugin-entity-feedback": "0.2.17", - "@backstage/plugin-entity-feedback-backend": "0.2.14", - "@backstage/plugin-entity-feedback-common": "0.1.3", - "@backstage/plugin-entity-validation": "0.1.19", - "@backstage/plugin-events-backend": "0.3.4", - "@backstage/plugin-events-backend-module-aws-sqs": "0.3.3", - "@backstage/plugin-events-backend-module-azure": "0.2.3", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.3", - "@backstage/plugin-events-backend-module-gerrit": "0.2.3", - "@backstage/plugin-events-backend-module-github": "0.2.3", - "@backstage/plugin-events-backend-module-gitlab": "0.2.3", - "@backstage/plugin-events-backend-test-utils": "0.1.27", - "@backstage/plugin-events-node": "0.3.3", - "@internal/plugin-todo-list": "1.0.26", - "@internal/plugin-todo-list-backend": "1.0.26", + "@backstage/plugin-events-backend": "0.3.5", + "@backstage/plugin-events-backend-module-aws-sqs": "0.3.4", + "@backstage/plugin-events-backend-module-azure": "0.2.4", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.4", + "@backstage/plugin-events-backend-module-gerrit": "0.2.4", + "@backstage/plugin-events-backend-module-github": "0.2.4", + "@backstage/plugin-events-backend-module-gitlab": "0.2.4", + "@backstage/plugin-events-backend-test-utils": "0.1.28", + "@backstage/plugin-events-node": "0.3.4", + "@internal/plugin-todo-list": "1.0.27", + "@internal/plugin-todo-list-backend": "1.0.27", "@internal/plugin-todo-list-common": "1.0.18", - "@backstage/plugin-explore": "0.4.20", - "@backstage/plugin-explore-backend": "0.0.27", - "@backstage/plugin-explore-common": "0.0.2", - "@backstage/plugin-explore-react": "0.0.38", - "@backstage/plugin-firehydrant": "0.2.18", - "@backstage/plugin-fossa": "0.2.66", - "@backstage/plugin-gcalendar": "0.3.27", - "@backstage/plugin-gcp-projects": "0.3.50", - "@backstage/plugin-git-release-manager": "0.3.46", - "@backstage/plugin-github-actions": "0.6.15", - "@backstage/plugin-github-deployments": "0.1.65", - "@backstage/plugin-github-issues": "0.4.1", - "@backstage/plugin-github-pull-requests-board": "0.2.0", - "@backstage/plugin-gitops-profiles": "0.3.49", - "@backstage/plugin-gocd": "0.1.40", - "@backstage/plugin-graphiql": "0.3.7", - "@backstage/plugin-graphql-voyager": "0.1.16", - "@backstage/plugin-home": "0.7.3", - "@backstage/plugin-home-react": "0.1.12", - "@backstage/plugin-ilert": "0.2.23", - "@backstage/plugin-jenkins": "0.9.9", - "@backstage/plugin-jenkins-backend": "0.4.4", - "@backstage/plugin-jenkins-common": "0.1.25", - "@backstage/plugin-kafka": "0.3.34", - "@backstage/plugin-kafka-backend": "0.3.15", - "@backstage/plugin-kubernetes": "0.11.9", - "@backstage/plugin-kubernetes-backend": "0.17.0", - "@backstage/plugin-kubernetes-cluster": "0.0.10", - "@backstage/plugin-kubernetes-common": "0.7.5", - "@backstage/plugin-kubernetes-node": "0.1.11", - "@backstage/plugin-kubernetes-react": "0.3.4", - "@backstage/plugin-lighthouse": "0.4.19", - "@backstage/plugin-lighthouse-backend": "0.4.10", - "@backstage/plugin-lighthouse-common": "0.1.5", - "@backstage/plugin-linguist": "0.1.19", - "@backstage/plugin-linguist-backend": "0.5.15", - "@backstage/plugin-linguist-common": "0.1.2", - "@backstage/plugin-microsoft-calendar": "0.1.16", - "@backstage/plugin-newrelic": "0.3.49", - "@backstage/plugin-newrelic-dashboard": "0.3.9", - "@backstage/plugin-nomad": "0.1.15", - "@backstage/plugin-nomad-backend": "0.1.19", - "@backstage/plugin-notifications": "0.2.0", - "@backstage/plugin-notifications-backend": "0.2.0", + "@backstage/plugin-home": "0.7.4", + "@backstage/plugin-home-react": "0.1.13", + "@backstage/plugin-kubernetes": "0.11.10", + "@backstage/plugin-kubernetes-backend": "0.17.1", + "@backstage/plugin-kubernetes-cluster": "0.0.11", + "@backstage/plugin-kubernetes-common": "0.7.6", + "@backstage/plugin-kubernetes-node": "0.1.12", + "@backstage/plugin-kubernetes-react": "0.3.5", + "@backstage/plugin-notifications": "0.2.1", + "@backstage/plugin-notifications-backend": "0.2.1", + "@backstage/plugin-notifications-backend-module-email": "0.0.1", "@backstage/plugin-notifications-common": "0.0.3", - "@backstage/plugin-notifications-node": "0.1.3", - "@backstage/plugin-octopus-deploy": "0.2.16", - "@backstage/plugin-opencost": "0.2.9", - "@backstage/plugin-org": "0.6.24", - "@backstage/plugin-org-react": "0.1.23", - "@backstage/plugin-pagerduty": "0.7.6", - "@backstage/plugin-periskop": "0.1.32", - "@backstage/plugin-periskop-backend": "0.2.15", - "@backstage/plugin-permission-backend": "0.5.41", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.14", + "@backstage/plugin-notifications-node": "0.1.4", + "@backstage/plugin-org": "0.6.25", + "@backstage/plugin-org-react": "0.1.24", + "@backstage/plugin-permission-backend": "0.5.42", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.15", "@backstage/plugin-permission-common": "0.7.13", - "@backstage/plugin-permission-node": "0.7.28", + "@backstage/plugin-permission-node": "0.7.29", "@backstage/plugin-permission-react": "0.4.22", - "@backstage/plugin-playlist": "0.2.8", - "@backstage/plugin-playlist-backend": "0.3.21", - "@backstage/plugin-playlist-common": "0.1.15", - "@backstage/plugin-proxy-backend": "0.4.15", - "@backstage/plugin-puppetdb": "0.1.17", - "@backstage/plugin-rollbar": "0.4.34", - "@backstage/plugin-rollbar-backend": "0.1.62", - "@backstage/plugin-scaffolder": "1.19.3", - "@backstage/plugin-scaffolder-backend": "1.22.4", - "@backstage/plugin-scaffolder-backend-module-azure": "0.1.9", - "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.2.7", - "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.1.7", - "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.1.7", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.18", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.41", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.9", - "@backstage/plugin-scaffolder-backend-module-gitea": "0.1.7", - "@backstage/plugin-scaffolder-backend-module-github": "0.2.7", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.3.3", - "@backstage/plugin-scaffolder-backend-module-rails": "0.4.34", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.25", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.3.0", - "@backstage/plugin-scaffolder-common": "1.5.1", - "@backstage/plugin-scaffolder-node": "0.4.3", - "@backstage/plugin-scaffolder-node-test-utils": "0.1.3", - "@backstage/plugin-scaffolder-react": "1.8.4", - "@backstage/plugin-search": "1.4.10", - "@backstage/plugin-search-backend": "1.5.7", - "@backstage/plugin-search-backend-module-catalog": "0.1.22", - "@backstage/plugin-search-backend-module-elasticsearch": "1.4.0", - "@backstage/plugin-search-backend-module-explore": "0.1.21", - "@backstage/plugin-search-backend-module-pg": "0.5.26", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.10", - "@backstage/plugin-search-backend-module-techdocs": "0.1.22", - "@backstage/plugin-search-backend-node": "1.2.21", + "@backstage/plugin-proxy-backend": "0.4.16", + "@backstage/plugin-scaffolder": "1.20.0", + "@backstage/plugin-scaffolder-backend": "1.22.6", + "@backstage/plugin-scaffolder-backend-module-azure": "0.1.10", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.2.8", + "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.1.8", + "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.1.8", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.19", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.42", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.10", + "@backstage/plugin-scaffolder-backend-module-gitea": "0.1.8", + "@backstage/plugin-scaffolder-backend-module-github": "0.2.8", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.4.0", + "@backstage/plugin-scaffolder-backend-module-notifications": "0.0.1", + "@backstage/plugin-scaffolder-backend-module-rails": "0.4.35", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.26", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.3.1", + "@backstage/plugin-scaffolder-common": "1.5.2", + "@backstage/plugin-scaffolder-node": "0.4.4", + "@backstage/plugin-scaffolder-node-test-utils": "0.1.4", + "@backstage/plugin-scaffolder-react": "1.8.5", + "@backstage/plugin-search": "1.4.11", + "@backstage/plugin-search-backend": "1.5.8", + "@backstage/plugin-search-backend-module-catalog": "0.1.24", + "@backstage/plugin-search-backend-module-elasticsearch": "1.4.1", + "@backstage/plugin-search-backend-module-explore": "0.1.24", + "@backstage/plugin-search-backend-module-pg": "0.5.27", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.11", + "@backstage/plugin-search-backend-module-techdocs": "0.1.23", + "@backstage/plugin-search-backend-node": "1.2.22", "@backstage/plugin-search-common": "1.2.11", - "@backstage/plugin-search-react": "1.7.10", - "@backstage/plugin-sentry": "0.5.19", - "@backstage/plugin-shortcuts": "0.3.23", - "@backstage/plugin-signals": "0.0.5", - "@backstage/plugin-signals-backend": "0.1.3", - "@backstage/plugin-signals-node": "0.1.3", + "@backstage/plugin-search-react": "1.7.11", + "@backstage/plugin-signals": "0.0.6", + "@backstage/plugin-signals-backend": "0.1.4", + "@backstage/plugin-signals-node": "0.1.4", "@backstage/plugin-signals-react": "0.0.3", - "@backstage/plugin-sonarqube": "0.7.16", - "@backstage/plugin-sonarqube-backend": "0.2.19", - "@backstage/plugin-sonarqube-react": "0.1.15", - "@backstage/plugin-splunk-on-call": "0.4.23", - "@backstage/plugin-stack-overflow": "0.1.29", - "@backstage/plugin-stack-overflow-backend": "0.2.21", - "@backstage/plugin-stackstorm": "0.1.15", - "@backstage/plugin-tech-insights": "0.3.26", - "@backstage/plugin-tech-insights-backend": "0.5.31", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.49", - "@backstage/plugin-tech-insights-common": "0.2.12", - "@backstage/plugin-tech-insights-node": "0.6.0", - "@backstage/plugin-tech-radar": "0.7.3", - "@backstage/plugin-techdocs": "1.10.4", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.31", - "@backstage/plugin-techdocs-backend": "1.10.4", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.9", - "@backstage/plugin-techdocs-node": "1.12.3", - "@backstage/plugin-techdocs-react": "1.2.3", - "@backstage/plugin-todo": "0.2.38", - "@backstage/plugin-todo-backend": "0.3.16", - "@backstage/plugin-user-settings": "0.8.5", - "@backstage/plugin-user-settings-backend": "0.2.16", - "@backstage/plugin-vault": "0.1.29", - "@backstage/plugin-vault-backend": "0.4.10", - "@backstage/plugin-vault-node": "0.1.10", - "@backstage/plugin-xcmetrics": "0.2.52", - "@backstage/plugin-catalog-backend-module-gitlab-org": "0.0.0" + "@backstage/plugin-techdocs": "1.10.5", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.32", + "@backstage/plugin-techdocs-backend": "1.10.5", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.10", + "@backstage/plugin-techdocs-node": "1.12.4", + "@backstage/plugin-techdocs-react": "1.2.4", + "@backstage/plugin-user-settings": "0.8.6", + "@backstage/plugin-user-settings-backend": "0.2.17" }, "changesets": [ - "afraid-needles-divide", - "bright-pumpkins-rule", - "chatty-cycles-unite", - "chilly-adults-sing", - "chilly-fireants-roll", - "cold-rats-leave", - "cool-elephants-march", - "cuddly-chairs-kick", - "curvy-planes-flash", - "dry-sloths-impress", - "eighty-apricots-kneel", - "eighty-bats-stare", - "eleven-pandas-divide", - "fix-stackoverflow", - "fluffy-hotels-wait", - "fresh-crews-impress", - "gold-waves-bake", - "gorgeous-cameras-cross", - "green-adults-push", - "hip-carrots-drive", - "itchy-gorillas-hope", - "itchy-keys-wonder", - "late-planes-fix", - "loud-frogs-eat", - "loud-vans-greet", - "lovely-games-cry", - "lucky-news-guess", - "orange-numbers-think", - "perfect-points-hope", - "proud-doors-cheat", - "purple-parents-sin", - "purple-waves-smile", - "rare-fireants-tickle", - "real-crabs-obey", - "renovate-0d0bd5c", - "selfish-pigs-glow", - "shy-students-clap", - "smart-avocados-invent", - "smooth-garlics-behave", - "sour-socks-approve", - "stupid-onions-know", - "tasty-apes-learn", - "thick-llamas-itch", - "tricky-cougars-shout", - "unlucky-days-play", - "unlucky-rivers-collect", - "warm-fans-promise", - "young-olives-drop" + "brave-apples-move", + "breezy-badgers-train", + "calm-cars-serve", + "calm-plums-wink", + "cold-seas-end", + "create-app-1716302437", + "create-app-1716903719", + "cyan-jobs-visit", + "cyan-paws-beg", + "cyan-snails-peel", + "eighty-kings-dress", + "eighty-yaks-switch", + "empty-spoons-tell", + "empty-tables-ring", + "famous-monkeys-count", + "forty-adults-roll", + "four-adults-mix", + "friendly-keys-fold", + "gentle-baboons-peel", + "gold-teachers-wink", + "great-cougars-guess", + "itchy-spoons-cry", + "large-months-decide", + "late-ants-impress", + "late-students-live", + "little-cooks-approve", + "loud-pumpkins-bow", + "lovely-hats-pay", + "lucky-taxis-rule", + "many-moles-sing", + "mean-laws-lay", + "neat-rivers-share", + "new-numbers-hug", + "nice-pants-shave", + "nine-hairs-kick", + "nine-ties-type", + "old-trees-check", + "olive-mangos-tickle", + "perfect-bikes-invite", + "polite-otters-talk", + "rude-kings-press", + "seven-geese-raise", + "shaggy-jokes-promise", + "six-llamas-give", + "slimy-fans-raise", + "smooth-gifts-nail", + "soft-flies-live", + "sour-colts-juggle", + "spicy-brooms-hang", + "spicy-camels-happen", + "spotty-plants-switch", + "strong-moose-work", + "stupid-tigers-bake", + "tall-lies-fetch", + "tall-pumas-teach", + "tender-seas-listen", + "thirty-plums-shout", + "tiny-pandas-return", + "warm-bees-hope", + "weak-gifts-occur", + "wet-crabs-guess", + "wild-doors-cheat", + "wild-ears-walk", + "wise-vans-sin", + "wise-wasps-look", + "young-camels-return" ] } diff --git a/.changeset/pretty-berries-live.md b/.changeset/pretty-berries-live.md new file mode 100644 index 0000000000..e83ebeef13 --- /dev/null +++ b/.changeset/pretty-berries-live.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-defaults': patch +'@backstage/backend-common': patch +--- + +Deprecated `dropDatabase` diff --git a/.changeset/proud-doors-cheat.md b/.changeset/proud-doors-cheat.md deleted file mode 100644 index 55ab7878d4..0000000000 --- a/.changeset/proud-doors-cheat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/theme': patch ---- - -Fixed bug where scrollbars don't pick up the theme when in dark mode diff --git a/.changeset/purple-parents-sin.md b/.changeset/purple-parents-sin.md deleted file mode 100644 index 4de90893ef..0000000000 --- a/.changeset/purple-parents-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-backstage-openapi': patch ---- - -Fix incorrect dependency import. diff --git a/.changeset/purple-waves-smile.md b/.changeset/purple-waves-smile.md deleted file mode 100644 index 44da72ea70..0000000000 --- a/.changeset/purple-waves-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-guest-provider': patch ---- - -Error if used outside of a development environment without explicit allowance diff --git a/.changeset/rare-fireants-tickle.md b/.changeset/rare-fireants-tickle.md deleted file mode 100644 index 8668d4c287..0000000000 --- a/.changeset/rare-fireants-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Added optional `initialShowDropDown` prop to `SidebarSubmenuItem` to internally manage the initial display state of the dropdown items. diff --git a/.changeset/real-crabs-obey.md b/.changeset/real-crabs-obey.md deleted file mode 100644 index 9a52f0e5a6..0000000000 --- a/.changeset/real-crabs-obey.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-explore': patch ---- - -Migrate search collator to use the new auth services. diff --git a/.changeset/real-ghosts-return.md b/.changeset/real-ghosts-return.md new file mode 100644 index 0000000000..9f81649254 --- /dev/null +++ b/.changeset/real-ghosts-return.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped TypeScript to version `5.4`. diff --git a/.changeset/renovate-0d0bd5c.md b/.changeset/renovate-0d0bd5c.md deleted file mode 100644 index ac3fe697f9..0000000000 --- a/.changeset/renovate-0d0bd5c.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-home-react': patch -'@backstage/plugin-home': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': patch ---- - -Updated dependency `@rjsf/utils` to `5.18.2`. -Updated dependency `@rjsf/core` to `5.18.2`. -Updated dependency `@rjsf/material-ui` to `5.18.2`. -Updated dependency `@rjsf/validator-ajv8` to `5.18.2`. diff --git a/.changeset/rude-kings-press.md b/.changeset/rude-kings-press.md new file mode 100644 index 0000000000..5c10753f8a --- /dev/null +++ b/.changeset/rude-kings-press.md @@ -0,0 +1,8 @@ +--- +'@backstage/backend-app-api': patch +--- + +Deprecated core service factories and implementations and moved them over to +subpath exports on `@backstage/backend-defaults` instead. E.g. +`@backstage/backend-defaults/scheduler` is where the service factory and default +implementation of `coreServices.scheduler` now lives. diff --git a/.changeset/selfish-pigs-glow.md b/.changeset/selfish-pigs-glow.md deleted file mode 100644 index c7808c0283..0000000000 --- a/.changeset/selfish-pigs-glow.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-auth-node': patch ---- - -Allow overriding default ownership resolving with the new `AuthOwnershipResolutionExtensionPoint` diff --git a/.changeset/selfish-pugs-lick.md b/.changeset/selfish-pugs-lick.md new file mode 100644 index 0000000000..1ac7ac7321 --- /dev/null +++ b/.changeset/selfish-pugs-lick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': patch +--- + +Import `tokenManager` definition from `@backstage/backend-plugin-api` diff --git a/.changeset/seven-geese-raise.md b/.changeset/seven-geese-raise.md new file mode 100644 index 0000000000..3d6e2347b9 --- /dev/null +++ b/.changeset/seven-geese-raise.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-search-backend-node': patch +'@backstage/plugin-search-backend': patch +--- + +Split backend search plugin startup into "init" and "start" stages to ensure necessary initialization has happened before startup diff --git a/.changeset/shaggy-jokes-promise.md b/.changeset/shaggy-jokes-promise.md new file mode 100644 index 0000000000..e7788b69f4 --- /dev/null +++ b/.changeset/shaggy-jokes-promise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend': patch +--- + +Move @backstage/repo-tools to devDependencies diff --git a/.changeset/shy-students-clap.md b/.changeset/shy-students-clap.md deleted file mode 100644 index 0e6244f21d..0000000000 --- a/.changeset/shy-students-clap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab-org': patch ---- - -Added a new `catalog-backend-module-gitlab-org` module which adds the `GitlabOrgDiscoveryEntityProvider` to the catalog's providers using the new backend system. diff --git a/.changeset/six-llamas-give.md b/.changeset/six-llamas-give.md new file mode 100644 index 0000000000..9bfbf52625 --- /dev/null +++ b/.changeset/six-llamas-give.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-defaults': minor +'@backstage/backend-common': minor +--- + +Deprecated and moved over core services to `@backstage/backend-defaults` diff --git a/.changeset/six-scissors-smile.md b/.changeset/six-scissors-smile.md deleted file mode 100644 index 7680edbba6..0000000000 --- a/.changeset/six-scissors-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -The `SignInPage` guest provider will now fall back to legacy guest auth if the backend request fails, allowing guest auth without a running backend. diff --git a/.changeset/slimy-fans-raise.md b/.changeset/slimy-fans-raise.md new file mode 100644 index 0000000000..782ef4bc82 --- /dev/null +++ b/.changeset/slimy-fans-raise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Fix weird opening behaviour of the component. diff --git a/.changeset/smart-avocados-invent.md b/.changeset/smart-avocados-invent.md deleted file mode 100644 index c71b6fef37..0000000000 --- a/.changeset/smart-avocados-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-dynamic-feature-service': patch ---- - -Updates the `scanRoot` method in the `PluginScanner` class to specifically ignore the `lost+found` directory, which is a system-generated directory used for file recovery on Unix-like systems. Skipping this directory avoids unnecessary errors. diff --git a/.changeset/smooth-garlics-behave.md b/.changeset/smooth-garlics-behave.md deleted file mode 100644 index ed972ae164..0000000000 --- a/.changeset/smooth-garlics-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Added option to `ServerTokenManager.fromConfig` that allows it to be instantiated in production without any configured keys. diff --git a/.changeset/smooth-gifts-nail.md b/.changeset/smooth-gifts-nail.md new file mode 100644 index 0000000000..aa2585bc4f --- /dev/null +++ b/.changeset/smooth-gifts-nail.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +'@backstage/backend-app-api': patch +--- + +Updating the logger redaction message to something less dramatic diff --git a/.changeset/soft-flies-live.md b/.changeset/soft-flies-live.md new file mode 100644 index 0000000000..b331269647 --- /dev/null +++ b/.changeset/soft-flies-live.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Add new `gitlab:pipeline:trigger` action to trigger GitLab pipelines. diff --git a/.changeset/sour-colts-juggle.md b/.changeset/sour-colts-juggle.md new file mode 100644 index 0000000000..35dc79452a --- /dev/null +++ b/.changeset/sour-colts-juggle.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Fix the logger service mock to prevent returning `undefined` from the `child` method. diff --git a/.changeset/sour-socks-approve.md b/.changeset/sour-socks-approve.md deleted file mode 100644 index db40806280..0000000000 --- a/.changeset/sour-socks-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Emit well known relationships for the Domain entity kind. diff --git a/.changeset/spicy-brooms-hang.md b/.changeset/spicy-brooms-hang.md new file mode 100644 index 0000000000..23f7da309b --- /dev/null +++ b/.changeset/spicy-brooms-hang.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Fixing bug in `formData` type as it should be `optional` as it's possibly undefined diff --git a/.changeset/spicy-camels-happen.md b/.changeset/spicy-camels-happen.md new file mode 100644 index 0000000000..1017f042ad --- /dev/null +++ b/.changeset/spicy-camels-happen.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +We are deprecating the legacy router handlers and contexts in preparation for the new backend system stable release. diff --git a/.changeset/spotty-plants-switch.md b/.changeset/spotty-plants-switch.md new file mode 100644 index 0000000000..a5951de05d --- /dev/null +++ b/.changeset/spotty-plants-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': minor +--- + +Migrate LDAP catalog module to the new backend system. diff --git a/.changeset/strong-moose-work.md b/.changeset/strong-moose-work.md new file mode 100644 index 0000000000..443b708e51 --- /dev/null +++ b/.changeset/strong-moose-work.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Add `--client-additional-properties` option to `openapi generate` command diff --git a/.changeset/stupid-onions-know.md b/.changeset/stupid-onions-know.md deleted file mode 100644 index 3d028557be..0000000000 --- a/.changeset/stupid-onions-know.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Empty descriptions are not rendered to improve the look&feel. diff --git a/.changeset/stupid-tigers-bake.md b/.changeset/stupid-tigers-bake.md new file mode 100644 index 0000000000..a4579ab05a --- /dev/null +++ b/.changeset/stupid-tigers-bake.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-kubernetes-backend': minor +'@backstage/plugin-kubernetes-common': minor +'@backstage/plugin-kubernetes-react': minor +--- + +Update kubernetes plugins to use autoscaling/v2 diff --git a/.changeset/tall-lies-fetch.md b/.changeset/tall-lies-fetch.md new file mode 100644 index 0000000000..a4484a5687 --- /dev/null +++ b/.changeset/tall-lies-fetch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Export `catalogTranslationRef` under `/alpha` diff --git a/.changeset/tall-pumas-teach.md b/.changeset/tall-pumas-teach.md new file mode 100644 index 0000000000..39e7c06297 --- /dev/null +++ b/.changeset/tall-pumas-teach.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Fixed a typo '$' in the review step label diff --git a/.changeset/tasty-apes-learn.md b/.changeset/tasty-apes-learn.md deleted file mode 100644 index 7a4545cf10..0000000000 --- a/.changeset/tasty-apes-learn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Fix to show web notifications even when browser is on foreground. Fix duplicate notifications with multiple tabs. diff --git a/.changeset/tender-seas-listen.md b/.changeset/tender-seas-listen.md new file mode 100644 index 0000000000..86b0bf4618 --- /dev/null +++ b/.changeset/tender-seas-listen.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-catalog': patch +--- + +updated the ContextMenu, ActionsPage, OngoingTask and TemplateCard frontend components to support the new scaffolder permissions: + +- `scaffolder.task.create` +- `scaffolder.task.cancel` +- `scaffolder.task.read` diff --git a/.changeset/thick-llamas-itch.md b/.changeset/thick-llamas-itch.md deleted file mode 100644 index 17d4fb23b6..0000000000 --- a/.changeset/thick-llamas-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Allow defining `className` and additional properties for `NotificationsSideBarItem` diff --git a/.changeset/thirty-plums-shout.md b/.changeset/thirty-plums-shout.md new file mode 100644 index 0000000000..56ac640326 --- /dev/null +++ b/.changeset/thirty-plums-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Added a regex test to check commit hash. If url is from git commit branch ignore the edit url. diff --git a/.changeset/tiny-pandas-return.md b/.changeset/tiny-pandas-return.md new file mode 100644 index 0000000000..cc9210a368 --- /dev/null +++ b/.changeset/tiny-pandas-return.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +`DefaultApiExplorerPage` now accepts an optional `ownerPickerMode` for toggling the behavior of the `EntityOwnerPicker`, exposing a new mode `` particularly suitable for larger catalogs. In this new mode, `EntityOwnerPicker` will display all the users and groups present in the catalog. diff --git a/.changeset/tricky-cougars-shout.md b/.changeset/tricky-cougars-shout.md deleted file mode 100644 index eed14c9eb8..0000000000 --- a/.changeset/tricky-cougars-shout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-explore': patch ---- - -Update README.md to point to explore plugin in community-plugins repository. diff --git a/.changeset/unlucky-days-play.md b/.changeset/unlucky-days-play.md deleted file mode 100644 index b847ebd2fc..0000000000 --- a/.changeset/unlucky-days-play.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Fix infinite loop in the notification title counter diff --git a/.changeset/unlucky-rivers-collect.md b/.changeset/unlucky-rivers-collect.md deleted file mode 100644 index c5ec865658..0000000000 --- a/.changeset/unlucky-rivers-collect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications-backend': patch ---- - -Updated documentation for sending messages by external services. diff --git a/.changeset/warm-bees-hope.md b/.changeset/warm-bees-hope.md new file mode 100644 index 0000000000..2a3de7fda7 --- /dev/null +++ b/.changeset/warm-bees-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +Renamed `BackendPluginConfig`, `BackendModuleConfig`, and `ExtensionPointConfig` respectively to `CreateBackendPluginOptions`, `CreateBackendModuleOptions`, and `CreateExtensionPointOptions` to standardize frontend and backend factories signatures. diff --git a/.changeset/warm-fans-promise.md b/.changeset/warm-fans-promise.md deleted file mode 100644 index a8a8f8a2c7..0000000000 --- a/.changeset/warm-fans-promise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -The rendered size of a notification is limited for very long descriptions. diff --git a/.changeset/weak-gifts-occur.md b/.changeset/weak-gifts-occur.md new file mode 100644 index 0000000000..7834c0a9d9 --- /dev/null +++ b/.changeset/weak-gifts-occur.md @@ -0,0 +1,10 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder-common': patch +--- + +added the following new permissions to the scaffolder backend endpoints: + +- `scaffolder.task.create` +- `scaffolder.task.cancel` +- `scaffolder.task.read` diff --git a/.changeset/wet-crabs-guess.md b/.changeset/wet-crabs-guess.md new file mode 100644 index 0000000000..c8a9282a47 --- /dev/null +++ b/.changeset/wet-crabs-guess.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/plugin-catalog-backend': patch +--- + +Start using the `isDatabaseConflictError` helper from the `@backstage/backend-plugin-api` package in order to avoid dependency with the soon to deprecate `@backstage/backend-common` package. diff --git a/.changeset/wild-doors-cheat.md b/.changeset/wild-doors-cheat.md new file mode 100644 index 0000000000..c302dde467 --- /dev/null +++ b/.changeset/wild-doors-cheat.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix `versions:check --fix` when `yarn.lock` has multiple joint versions in the same section diff --git a/.changeset/wild-ears-walk.md b/.changeset/wild-ears-walk.md new file mode 100644 index 0000000000..072c545f1a --- /dev/null +++ b/.changeset/wild-ears-walk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications-backend': minor +--- + +adding filtering of notifications by processors diff --git a/.changeset/wise-vans-sin.md b/.changeset/wise-vans-sin.md new file mode 100644 index 0000000000..37565c9300 --- /dev/null +++ b/.changeset/wise-vans-sin.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Deprecate legacy service logger helpers and stop using `getVoidLogger` in tests. diff --git a/.changeset/wise-wasps-look.md b/.changeset/wise-wasps-look.md new file mode 100644 index 0000000000..34f52b3a7b --- /dev/null +++ b/.changeset/wise-wasps-look.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Change owner to project for azure host diff --git a/.changeset/young-camels-return.md b/.changeset/young-camels-return.md new file mode 100644 index 0000000000..efdd822788 --- /dev/null +++ b/.changeset/young-camels-return.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Bump `esbuild` target for package builds to `ES2022`. diff --git a/.changeset/young-olives-drop.md b/.changeset/young-olives-drop.md deleted file mode 100644 index 4058293be8..0000000000 --- a/.changeset/young-olives-drop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -Removed explicit `toString()` method from `ServiceRef` type. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9fc63fbd04..9cd3bc0690 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -61,6 +61,7 @@ yarn.lock @backstage/maintainers @backst /plugins/linguist-common @backstage/maintainers @backstage/reviewers @awanlin /plugins/notifications @backstage/maintainers @backstage/notifications-maintainers /plugins/notifications-* @backstage/maintainers @backstage/notifications-maintainers +/plugins/scaffolder-backend-module-notifications @backstage/maintainers @backstage/notifications-maintainers /plugins/octopus-deploy @backstage/maintainers @backstage/reviewers @jmezach /plugins/permission-* @backstage/permission-maintainers /plugins/playlist @backstage/maintainers @backstage/reviewers @kuangp diff --git a/.github/renovate.json5 b/.github/renovate.json5 index a9cb54912a..5a70a25512 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -62,9 +62,21 @@ matchPackageNames: ['p-limit'], allowedVersions: '<4.0.0', }, + { + matchPackageNames: ['p-throttle'], + allowedVersions: '<4.0.0', + }, { matchPackageNames: ['p-queue'], allowedVersions: '<7.0.0', }, + { + matchPackageNames: ['serialize-error'], + allowedVersions: '<9.0.0', + }, + { + matchPackageNames: ['yn'], + allowedVersions: '<5.0.0', + }, ], } diff --git a/.github/uffizzi/k8s/manifests/backstage-crb.yaml b/.github/uffizzi/k8s/manifests/backstage-crb.yaml deleted file mode 100644 index a5dad3408a..0000000000 --- a/.github/uffizzi/k8s/manifests/backstage-crb.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: backstage-cluster-ro -subjects: - - namespace: backstage - kind: ServiceAccount - name: backstage-service-account -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:aggregate-to-view diff --git a/.github/uffizzi/k8s/manifests/backstage-deploy.yaml b/.github/uffizzi/k8s/manifests/backstage-deploy.yaml deleted file mode 100644 index 2c1458cfea..0000000000 --- a/.github/uffizzi/k8s/manifests/backstage-deploy.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: backstage -spec: - replicas: 1 - selector: - matchLabels: - app: backstage - template: - metadata: - labels: - app: backstage - spec: - serviceAccountName: backstage-service-account - containers: - - name: backstage - image: backstage - command: - - /bin/sh - args: - - '-c' - - "APP_CONFIG_app_baseUrl=$$UFFIZZI_URL APP_CONFIG_backend_baseUrl=$$UFFIZZI_URL APP_CONFIG_auth_environment='production' node packages/backend --config app-config.yaml" - imagePullPolicy: IfNotPresent - ports: - - name: http - containerPort: 7007 - envFrom: - - secretRef: - name: postgres-secrets - env: - - name: POSTGRES_PORT - value: '5432' - - name: POSTGRES_HOST - value: 'postgres.default.svc.cluster.local' - - name: NODE_ENV - value: production - resources: - limits: - cpu: 1000m - memory: 384Mi - requests: - cpu: 20m - memory: 160Mi diff --git a/.github/uffizzi/k8s/manifests/backstage-ingress.yaml b/.github/uffizzi/k8s/manifests/backstage-ingress.yaml deleted file mode 100644 index 8a7f58c524..0000000000 --- a/.github/uffizzi/k8s/manifests/backstage-ingress.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: backstage -spec: - ingressClassName: uffizzi - rules: - - host: backstage.example.com - http: - paths: - - backend: - service: - name: backstage - port: - number: 80 - path: / - pathType: Prefix - tls: - - hosts: - - backstage.example.com diff --git a/.github/uffizzi/k8s/manifests/backstage-sa.yaml b/.github/uffizzi/k8s/manifests/backstage-sa.yaml deleted file mode 100644 index db0b5bde38..0000000000 --- a/.github/uffizzi/k8s/manifests/backstage-sa.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: backstage-service-account - namespace: default diff --git a/.github/uffizzi/k8s/manifests/backstage-svc.yaml b/.github/uffizzi/k8s/manifests/backstage-svc.yaml deleted file mode 100644 index 1f4abc79b4..0000000000 --- a/.github/uffizzi/k8s/manifests/backstage-svc.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: backstage -spec: - selector: - app: backstage - ports: - - name: http - port: 80 - targetPort: http diff --git a/.github/uffizzi/k8s/manifests/kustomization.yaml b/.github/uffizzi/k8s/manifests/kustomization.yaml deleted file mode 100644 index d4db0e97b2..0000000000 --- a/.github/uffizzi/k8s/manifests/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backstage-deploy.yaml - - backstage-crb.yaml - - backstage-ingress.yaml - - backstage-sa.yaml - - backstage-svc.yaml - - pg-svc.yaml - - pg-deploy.yaml - - pg-secret.yaml - - pg-volume.yaml diff --git a/.github/uffizzi/k8s/manifests/pg-deploy.yaml b/.github/uffizzi/k8s/manifests/pg-deploy.yaml deleted file mode 100644 index 950e64283f..0000000000 --- a/.github/uffizzi/k8s/manifests/pg-deploy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# kubernetes/postgres.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres -spec: - replicas: 1 - selector: - matchLabels: - app: postgres - template: - metadata: - labels: - app: postgres - spec: - containers: - - name: postgres - image: postgres:12-alpine - imagePullPolicy: 'IfNotPresent' - ports: - - containerPort: 5432 - env: - - name: PGDATA - value: '/data/pgdata' - envFrom: - - secretRef: - name: postgres-secrets - resources: - limits: - cpu: 1000m - memory: 256Mi - requests: - cpu: 10m - memory: 96Mi - volumeMounts: - - mountPath: /data - name: postgresdb - volumes: - - name: postgresdb - persistentVolumeClaim: - claimName: postgres-storage-claim diff --git a/.github/uffizzi/k8s/manifests/pg-secret.yaml b/.github/uffizzi/k8s/manifests/pg-secret.yaml deleted file mode 100644 index 28a31f7c53..0000000000 --- a/.github/uffizzi/k8s/manifests/pg-secret.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: postgres-secrets -type: Opaque -data: - POSTGRES_USER: YmFja3N0YWdl - POSTGRES_PASSWORD: aHVudGVyMg== diff --git a/.github/uffizzi/k8s/manifests/pg-svc.yaml b/.github/uffizzi/k8s/manifests/pg-svc.yaml deleted file mode 100644 index ab7e192a65..0000000000 --- a/.github/uffizzi/k8s/manifests/pg-svc.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: postgres -spec: - selector: - app: postgres - ports: - - port: 5432 diff --git a/.github/uffizzi/k8s/manifests/pg-volume.yaml b/.github/uffizzi/k8s/manifests/pg-volume.yaml deleted file mode 100644 index 0dcb317e50..0000000000 --- a/.github/uffizzi/k8s/manifests/pg-volume.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-storage-claim -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2G diff --git a/.github/uffizzi/uffizzi.production.app-config.yaml b/.github/uffizzi/uffizzi.production.app-config.yaml deleted file mode 100644 index 53944256e1..0000000000 --- a/.github/uffizzi/uffizzi.production.app-config.yaml +++ /dev/null @@ -1,297 +0,0 @@ -app: - title: Backstage Uffizzi Environment - baseUrl: ${UFFIZZI_URL} - -organization: - name: My Company - -backend: - baseUrl: ${UFFIZZI_URL} - auth: - keys: - # random mock key for Uffizzi deployments - - secret: 5TXvdjVZFxF7qf9K5RAYRDoGrLzJooqa - listen: - port: 7007 - database: - client: pg - connection: - host: ${POSTGRES_HOST} - port: ${POSTGRES_PORT} - user: ${POSTGRES_USER} - password: ${POSTGRES_PASSWORD} - cors: - origin: ${UFFIZZI_URL} - methods: [GET, HEAD, PATCH, POST, PUT, DELETE] - credentials: true - csp: - connect-src: ["'self'", 'http:', 'https:'] - img-src: ["'self'", 'data:', 'https://cdnjs.cloudflare.com'] - # Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference - # Default Helmet Content-Security-Policy values can be removed by setting the key to false - -auth: - environment: production - providers: {} - proxy: - enabled: true - url: https://demo.backstage.io/api/auth - -catalog: - rules: - - allow: - - Component - - API - - Resource - - System - - Domain - - Location - locations: - - type: url - target: https://github.com/backstage/backstage/blob/${REF_NAME}/packages/catalog-model/examples/all.yaml - - - type: url - target: https://github.com/backstage/backstage/blob/${REF_NAME}/plugins/techdocs-backend/examples/documented-component-uffizzi/catalog-info.yaml - - - type: url - target: https://github.com/backstage/backstage/blob/${REF_NAME}/packages/catalog-model/examples/acme-corp.yaml - rules: - - allow: [User, Group] - - - type: url - target: https://github.com/backstage/backstage/blob/${REF_NAME}/plugins/scaffolder-backend/sample-templates/all-templates.yaml - rules: - - allow: [Template] - -proxy: - endpoints: - '/circleci/api': - target: https://circleci.com/api/v1.1 - headers: - Circle-Token: ${CIRCLECI_AUTH_TOKEN} - - '/jenkins/api': - target: http://localhost:8080 - headers: - Authorization: ${JENKINS_BASIC_AUTH_HEADER} - - '/travisci/api': - target: https://api.travis-ci.com - changeOrigin: true - headers: - Authorization: ${TRAVISCI_AUTH_TOKEN} - travis-api-version: '3' - - '/newrelic/apm/api': - target: https://api.newrelic.com/v2 - headers: - X-Api-Key: ${NEW_RELIC_REST_API_KEY} - - '/newrelic/api': - target: https://api.newrelic.com - headers: - X-Api-Key: ${NEW_RELIC_USER_KEY} - - '/pagerduty': - target: https://api.pagerduty.com - headers: - Authorization: Token token=${PAGERDUTY_TOKEN} - - '/buildkite/api': - target: https://api.buildkite.com/v2/ - headers: - Authorization: ${BUILDKITE_TOKEN} - - '/sentry/api': - target: https://sentry.io/api/ - allowedMethods: ['GET'] - headers: - Authorization: ${SENTRY_TOKEN} - - '/ilert': - target: https://api.ilert.com - allowedMethods: ['GET', 'POST', 'PUT'] - allowedHeaders: ['Authorization'] - headers: - Authorization: ${ILERT_AUTH_HEADER} - - '/airflow': - target: https://your.airflow.instance.com/api/v1 - headers: - Authorization: ${AIRFLOW_BASIC_AUTH_HEADER} - - '/gocd': - target: https://your.gocd.instance.com/go/api - allowedMethods: ['GET'] - allowedHeaders: ['Authorization'] - headers: - Authorization: Basic ${GOCD_AUTH_CREDENTIALS} - - '/dynatrace': - target: https://your.dynatrace.instance.com/api/v2 - headers: - Authorization: 'Api-Token ${DYNATRACE_ACCESS_TOKEN}' - -techdocs: - builder: 'local' # Alternatives - 'external' - generator: - runIn: 'local' - # dockerImage: my-org/techdocs # use a custom docker image - # pullImage: true # or false to disable automatic pulling of image (e.g. if custom docker login is required) - publisher: - type: 'local' # Alternatives - 'googleGcs' or 'awsS3' or 'azureBlobStorage' or 'openStackSwift'. Read documentation for using alternatives. - -dynatrace: - baseUrl: https://your.dynatrace.instance.com - -nomad: - addr: 0.0.0.0 - -# Score-cards sample configuration. -scorecards: - jsonDataUrl: https://raw.githubusercontent.com/Oriflame/backstage-plugins/main/plugins/score-card/sample-data/ - wikiLinkTemplate: https://link-to-wiki/{id} - -sentry: - organization: my-company - -rollbar: - organization: my-company - # NOTE: The rollbar-backend & accountToken key may be deprecated in the future (replaced by a proxy config) - accountToken: my-rollbar-account-token - -lighthouse: - baseUrl: http://localhost:3003 - -kubernetes: - serviceLocatorMethod: - type: 'multiTenant' - clusterLocatorMethods: - - type: 'config' - clusters: - - url: ${UFFIZZI_CLUSTER_APISERVER} - name: uffizzi - authProvider: 'serviceAccount' - -kafka: - clientId: backstage - clusters: - - name: cluster - dashboardUrl: https://akhq.io/ - brokers: - - localhost:9092 - -allure: - baseUrl: http://localhost:5050/allure-docker-service - -integrations: - github: - - host: github.com - token: ${GITHUB_TOKEN} - ### Example for how to add your GitHub Enterprise instance using the API: - # - host: ghe.example.net - # apiBaseUrl: https://ghe.example.net/api/v3 - # token: ${GHE_TOKEN} - ### Example for how to add your GitHub Enterprise instance using raw HTTP fetches (token is optional): - # - host: ghe.example.net - # rawBaseUrl: https://ghe.example.net/raw - # token: ${GHE_TOKEN} - gitlab: - - host: gitlab.com - token: ${GITLAB_TOKEN} - ### Example for how to add a bitbucket cloud integration - # bitbucketCloud: - # - username: ${BITBUCKET_USERNAME} - # appPassword: ${BITBUCKET_APP_PASSWORD} - ### Example for how to add your bitbucket server instance using the API: - # - host: server.bitbucket.com - # apiBaseUrl: server.bitbucket.com - # username: ${BITBUCKET_SERVER_USERNAME} - # appPassword: ${BITBUCKET_SERVER_APP_PASSWORD} - azure: - - host: dev.azure.com - token: ${AZURE_TOKEN} - # googleGcs: - # clientEmail: 'example@example.com' - # privateKey: ${GCS_PRIVATE_KEY} - awsS3: - - host: amazonaws.com - accessKeyId: ${AWS_ACCESS_KEY_ID} - secretAccessKey: ${AWS_SECRET_ACCESS_KEY} - -costInsights: - engineerCost: 200000 - engineerThreshold: 0.5 - products: - computeEngine: - name: Compute Engine - icon: compute - cloudDataflow: - name: Cloud Dataflow - icon: data - cloudStorage: - name: Cloud Storage - icon: storage - bigQuery: - name: BigQuery - icon: search - events: - name: Events - icon: data - metrics: - DAU: - name: Daily Active Users - default: true - MSC: - name: Monthly Subscribers - currencies: - engineers: - label: 'Engineers 🛠' - unit: 'engineer' - usd: - label: 'US Dollars 💵' - kind: 'USD' - unit: 'dollar' - prefix: '$' - rate: 1 - carbonOffsetTons: - label: 'Carbon Offset Tons ♻️⚖️s' - kind: 'CARBON_OFFSET_TONS' - unit: 'carbon offset ton' - rate: 3.5 - beers: - label: 'Beers 🍺' - kind: 'BEERS' - unit: 'beer' - rate: 4.5 - pintsIceCream: - label: 'Pints of Ice Cream 🍦' - kind: 'PINTS_OF_ICE_CREAM' - unit: 'ice cream pint' - rate: 5.5 -pagerduty: - eventsBaseUrl: 'https://events.pagerduty.com/v2' -jenkins: - instances: - - name: default - baseUrl: https://jenkins.example.com - username: backstage-bot - apiKey: 123456789abcdef0123456789abcedf012 - -azureDevOps: - host: dev.azure.com - token: my-token - organization: my-company - -apacheAirflow: - baseUrl: https://your.airflow.instance.com - -gocd: - baseUrl: https://your.gocd.instance.com - -permission: - enabled: true - -search: - query: - pageLimit: 50 diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 026e5a9b18..f2fe96f3ab 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -152,6 +152,8 @@ graphviz Hackathons haproxy hardcoded +Harness +harness Helidon Henneke Heroku @@ -433,7 +435,6 @@ transpilers truthy TSDoc typeahead -Uffizzi ui unbreak Unconference @@ -445,6 +446,7 @@ unregistering unregistration untracked upsert +upstreams upvote URIs url @@ -464,6 +466,7 @@ Weaveworks Webpack widget's winston +Wolfi www WWW XCMetrics diff --git a/.github/workflows/api-breaking-changes-comment.yml b/.github/workflows/api-breaking-changes-comment.yml new file mode 100644 index 0000000000..9ae32e1d4a --- /dev/null +++ b/.github/workflows/api-breaking-changes-comment.yml @@ -0,0 +1,111 @@ +name: API Breaking Changes (comment) + +on: + workflow_run: + workflows: + - 'API Breaking Changes (Trigger)' + types: + - completed + +jobs: + setup: + name: Add values from previous step + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + permissions: + # "If you specify the access for any of these scopes, all of those that are not specified are set to none." + # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions + actions: read # Access cache + outputs: + git-ref: ${{ steps.event.outputs.GIT_REF }} + pr-number: ${{ steps.event.outputs.PR_NUMBER }} + action: ${{ steps.event.outputs.ACTION }} + steps: + - name: Harden Runner + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 + + - name: 'Download artifacts' + # Fetch output (zip archive) from the workflow run that triggered this workflow. + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "preview-spec" + })[0]; + if (matchArtifact === undefined) { + throw TypeError('Build Artifact not found!'); + } + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + let fs = require('fs'); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data)); + + - name: 'Accept event from first stage' + run: unzip preview-spec.zip event.json + + - name: Read Event into ENV + id: event + run: | + echo PR_NUMBER=$(jq '.number | tonumber' < event.json) >> $GITHUB_OUTPUT + echo ACTION=$(jq --raw-output '.action | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT + echo GIT_REF=$(jq --raw-output '.pull_request.head.sha | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT + + - name: DEBUG - Print Job Outputs + if: ${{ runner.debug }} + run: | + echo "PR number: ${{ steps.event.outputs.PR_NUMBER }}" + echo "Git Ref: ${{ steps.event.outputs.GIT_REF }}" + echo "Action: ${{ steps.event.outputs.ACTION }}" + cat event.json + + - name: Get Comment + id: get-comment + run: | + unzip preview-spec.zip comment.md + ls + grep + + add-comment: + name: Write comment about issues + needs: + - setup + if: ${{ github.event.workflow_run.conclusion == 'success' }} + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + + # Identify comment to be updated + - name: Find comment for API Changes + uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3 + id: find-comment + with: + issue-number: ${{ needs.setup.outputs.pr-number }} + comment-author: 'github-actions[bot]' + body-includes: API changes + direction: last + + - name: Create or Update Comment with API Changes + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body-path: comment.md + edit-mode: replace diff --git a/.github/workflows/api-breaking-changes.yml b/.github/workflows/api-breaking-changes.yml new file mode 100644 index 0000000000..d44e524ccb --- /dev/null +++ b/.github/workflows/api-breaking-changes.yml @@ -0,0 +1,56 @@ +name: API Breaking Changes (Trigger) +on: + pull_request: + types: [opened, synchronize, reopened, closed] + paths: + - '**/openapi.yaml' + +jobs: + get-backstage-changes: + env: + NODE_OPTIONS: --max-old-space-size=4096 + name: Build PR image + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }} + steps: + - name: Harden Runner + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 + with: + egress-policy: audit + + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + with: + # Fetch the commit that's merged into the base rather than the target ref + # This will let us diff only the contents of the PR, without fetching more history + ref: 'refs/pull/${{ github.event.pull_request.number }}/merge' + - name: fetch base + run: git fetch --depth 1 origin ${{ github.base_ref }} + + - name: setup-node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: 18.x + registry-url: https://registry.npmjs.org/ + + - name: yarn install + uses: backstage/actions/yarn-install@a674369920067381b450d398b27df7039b7ef635 # v0.6.5 + with: + cache-prefix: linux-v18 + + - name: breaking changes check + run: | + yarn backstage-repo-tools repo schema openapi diff --since origin/${{ github.base_ref }} > comment.md + + - name: clone artifacts to current directory + run: | + cat ${{ github.event_path }} > event.json + + - name: Upload Artifacts + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4 + with: + name: preview-spec + path: | + comment.md + event.json + retention-days: 2 + overwrite: true diff --git a/.github/workflows/automate_area-labels.yml b/.github/workflows/automate_area-labels.yml index 632624bd50..74f577f360 100644 --- a/.github/workflows/automate_area-labels.yml +++ b/.github/workflows/automate_area-labels.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index 4d965499d2..95b0a808a1 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -23,11 +23,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: # Fetch the commit that's merged into the base rather than the target ref # This will let us diff only the contents of the PR, without fetching more history diff --git a/.github/workflows/automate_merge_message.yml b/.github/workflows/automate_merge_message.yml index 38243ee0ac..a53369c884 100644 --- a/.github/workflows/automate_merge_message.yml +++ b/.github/workflows/automate_merge_message.yml @@ -24,11 +24,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: ref: '${{ github.event.pull_request.merge_commit_sha }}' diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index c7674e853d..afb8f3b838 100644 --- a/.github/workflows/automate_stale.yml +++ b/.github/workflows/automate_stale.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/ci-noop.yml b/.github/workflows/ci-noop.yml index 2c66da768f..4dc8594bc9 100644 --- a/.github/workflows/ci-noop.yml +++ b/.github/workflows/ci-noop.yml @@ -40,7 +40,7 @@ jobs: name: Test ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdd31b2d57..00181adb5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,11 +28,11 @@ jobs: name: Install ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -64,11 +64,11 @@ jobs: name: Verify ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -187,6 +187,15 @@ jobs: --health-retries 5 ports: - 3306/tcp + redis: + image: redis:7 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 6379/tcp env: CI: true @@ -197,7 +206,7 @@ jobs: INTEGRATION_TEST_AZURE_TOKEN: ${{ secrets.INTEGRATION_TEST_AZURE_TOKEN }} steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: fetch master branch run: git fetch origin master @@ -231,6 +240,7 @@ jobs: BACKSTAGE_TEST_DATABASE_POSTGRES16_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres16.ports[5432] }} BACKSTAGE_TEST_DATABASE_POSTGRES12_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres12.ports[5432] }} BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING: mysql://root:root@localhost:${{ job.services.mysql8.ports[3306] }}/ignored + BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING: redis://localhost:${{ job.services.redis.ports[6379] }} # We run the test cases before verifying the specs to prevent any failing tests from causing errors. - name: verify openapi specs against test cases diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index c32d50ced5..7dcb4a9c0f 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index 020254c872..ddf01fa49c 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -20,12 +20,12 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - name: checkout - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: path: backstage ref: ${{ github.event.client_payload.version && env.RELEASE_VERSION || github.ref }} diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index 6864ec67dc..fd7766e643 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -24,11 +24,11 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js 18.x uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -66,7 +66,7 @@ jobs: run: ls microsite/build && ls microsite/build/storybook - name: Deploy both microsite and storybook to gh-pages - uses: JamesIves/github-pages-deploy-action@ec9c88baef04b842ca6f0a132fd61c762aa6c1b0 # v4.6.0 + uses: JamesIves/github-pages-deploy-action@5c6e9e9f3672ce8fd37b9856193d2a537941e66c # v4.6.1 with: branch: gh-pages folder: microsite/build diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml index 07c3db0f11..02a1c65681 100644 --- a/.github/workflows/deploy_nightly.yml +++ b/.github/workflows/deploy_nightly.yml @@ -15,11 +15,11 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js 18.x uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index 775d8d00f8..04badd65b0 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -55,6 +55,15 @@ jobs: --health-retries 5 ports: - 3306/tcp + redis: + image: redis:7 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 6379/tcp env: CI: true @@ -65,7 +74,7 @@ jobs: INTEGRATION_TEST_AZURE_TOKEN: ${{ secrets.INTEGRATION_TEST_AZURE_TOKEN }} steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -105,16 +114,17 @@ jobs: - name: test (and upload coverage) run: | yarn backstage-cli repo test --maxWorkers=3 --workerIdleMemoryLimit=1300M --coverage - bash <(curl -s https://codecov.io/bash) + # bash <(curl -s https://codecov.io/bash) # Upload code coverage for some specific flags. Also see .codecov.yml - bash <(curl -s https://codecov.io/bash) -f packages/core-app-api/coverage/* -F core-app-api - bash <(curl -s https://codecov.io/bash) -f packages/core-components/coverage/* -F core-components - bash <(curl -s https://codecov.io/bash) -f packages/core-plugin-api/coverage/* -F core-plugin-api + # bash <(curl -s https://codecov.io/bash) -f packages/core-app-api/coverage/* -F core-app-api + # bash <(curl -s https://codecov.io/bash) -f packages/core-components/coverage/* -F core-components + # bash <(curl -s https://codecov.io/bash) -f packages/core-plugin-api/coverage/* -F core-plugin-api env: BACKSTAGE_TEST_DISABLE_DOCKER: 1 BACKSTAGE_TEST_DATABASE_POSTGRES16_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres16.ports[5432] }} BACKSTAGE_TEST_DATABASE_POSTGRES12_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres12.ports[5432] }} BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING: mysql://root:root@localhost:${{ job.services.mysql8.ports[3306] }}/ignored + BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING: redis://localhost:${{ job.services.redis.ports[6379] }} - name: Discord notification if: ${{ failure() }} @@ -144,11 +154,11 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index f8f5efacc4..7afc0a81bb 100644 --- a/.github/workflows/issue.yaml +++ b/.github/workflows/issue.yaml @@ -10,7 +10,7 @@ jobs: if: github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/pr-review-comment-trigger.yaml b/.github/workflows/pr-review-comment-trigger.yaml index 46f7dad8a3..bea1618608 100644 --- a/.github/workflows/pr-review-comment-trigger.yaml +++ b/.github/workflows/pr-review-comment-trigger.yaml @@ -20,7 +20,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit @@ -30,7 +30,8 @@ jobs: run: | mkdir -p ./pr echo $PR_NUMBER > ./pr/pr_number - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: pr_number-${{ github.event.pull_request.number }} path: pr/ + overwrite: true diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml index 72256a8c6e..232089e2f3 100644 --- a/.github/workflows/pr-review-comment.yaml +++ b/.github/workflows/pr-review-comment.yaml @@ -17,7 +17,7 @@ jobs: steps: # Inspired by https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 3aa20b1c96..779137b52a 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -18,7 +18,7 @@ jobs: if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request ) steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 91f1b02fee..8d5b2522af 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,17 +29,17 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - name: 'Checkout code' - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: persist-credentials: false - name: 'Run analysis' - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 with: results_file: results.sarif results_format: sarif @@ -58,14 +58,15 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: 'Upload artifact' - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: SARIF file path: results.sarif retention-days: 5 + overwrite: true # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/upload-sarif@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 with: sarif_file: results.sarif diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index 5dbd0361c1..bb2e00ffa6 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -10,11 +10,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: # Fetch changes to previous commit - required for 'only_changed' in Prettier action fetch-depth: 0 diff --git a/.github/workflows/sync_dependabot-changesets.yml b/.github/workflows/sync_dependabot-changesets.yml index 8b3be335ed..0102cf316a 100644 --- a/.github/workflows/sync_dependabot-changesets.yml +++ b/.github/workflows/sync_dependabot-changesets.yml @@ -11,12 +11,12 @@ jobs: if: github.actor == 'dependabot[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - name: Checkout - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: fetch-depth: 2 ref: ${{ github.head_ref }} diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index b0a2499d43..1f58969202 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit @@ -21,7 +21,7 @@ jobs: run: npm install semver@7.3.5 fs-extra@10.0.0 @manypkg/get-packages@1.1.1 - name: Checkout - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: path: backstage # 'v' prefix is added here for the tag, we keep it out of the manifest logic @@ -29,7 +29,7 @@ jobs: # Checkout backstage/versions into /backstage/versions, which is where store the output - name: Checkout versions - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: repository: backstage/versions path: backstage/versions diff --git a/.github/workflows/sync_renovate-changesets.yml b/.github/workflows/sync_renovate-changesets.yml index d02e35483c..01e6ee6dfc 100644 --- a/.github/workflows/sync_renovate-changesets.yml +++ b/.github/workflows/sync_renovate-changesets.yml @@ -11,12 +11,12 @@ jobs: if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - name: Checkout - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: fetch-depth: 2 ref: ${{ github.head_ref }} diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index d5a4048044..cb5eaa1737 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -12,11 +12,11 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js 18.x uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index 70fb8a44d9..4678c36907 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -25,11 +25,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Monitor and Synchronize Snyk Policies uses: snyk/actions/node@8349f9043a8b7f0f3ee8885bf28f0b388d2446e8 # master with: @@ -58,6 +58,6 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} NODE_OPTIONS: --max-old-space-size=7168 - name: Upload Snyk report - uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/upload-sarif@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 with: sarif_file: snyk.sarif diff --git a/.github/workflows/sync_version-packages.yml b/.github/workflows/sync_version-packages.yml index b2ad80b6da..a7f8d3674e 100644 --- a/.github/workflows/sync_version-packages.yml +++ b/.github/workflows/sync_version-packages.yml @@ -14,11 +14,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: fetch-depth: 20000 fetch-tags: true diff --git a/.github/workflows/uffizzi-build.yml b/.github/workflows/uffizzi-build.yml deleted file mode 100644 index 4a52af21bc..0000000000 --- a/.github/workflows/uffizzi-build.yml +++ /dev/null @@ -1,129 +0,0 @@ -name: Preview (build) -on: - pull_request: - types: [opened, synchronize, reopened, closed] - paths-ignore: - - '.changeset/**' - - 'contrib/**' - - 'docs/**' - - 'microsite/**' - - 'beps/**' - - 'scripts/**' - - 'storybook/**' - - '**/*.test.*' - - '**/package.json' - - '*.md' - -jobs: - build-backstage: - env: - NODE_OPTIONS: --max-old-space-size=4096 - UFFIZZI_URL: https://app.uffizzi.com - name: Build PR image - runs-on: ubuntu-latest - if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }} - outputs: - tags: ${{ steps.meta.outputs.tags }} - steps: - - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 - with: - egress-policy: audit - - - name: checkout - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 - - - name: setup-node - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: 18.x - registry-url: https://registry.npmjs.org/ - - - name: yarn install - uses: backstage/actions/yarn-install@af61233abb88019335b07ab855873d991f43d25a # v0.6.7 - with: - cache-prefix: linux-v18 - - - name: Use Uffizzi's backstage app config - run: | - cp -f ./.github/uffizzi/uffizzi.production.app-config.yaml ./app-config.yaml - - - name: backstage build - run: | - yarn workspace example-backend build - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - - name: Generate UUID image name - id: uuid - run: echo "UUID_TAG_APP=backstage-$(uuidgen --time)" >> $GITHUB_ENV - - - name: Docker metadata - id: meta - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 - with: - images: registry.uffizzi.com/${{ env.UUID_TAG_APP }} - tags: type=raw,value=60d - - - name: Build Image - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - context: . - file: packages/backend/Dockerfile - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - push: true - cache-from: type=gha - cache-to: type=gha,mode=max - - render-kustomize: - name: Render Kustomize Manifests - runs-on: ubuntu-latest - needs: - - build-backstage - steps: - - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 - with: - egress-policy: audit - - - name: Checkout git repo - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 - - name: Render Compose File - run: | - # update image after the build above - cd ./.github/uffizzi/k8s/manifests - kustomize edit set image backstage=${{ needs.build-backstage.outputs.tags }} - kustomize build . > manifests.rendered.yml - cat manifests.rendered.yml - - name: Upload Rendered Manifests File as Artifact - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3 - with: - name: preview-spec - path: ./.github/uffizzi/k8s/manifests/manifests.rendered.yml - retention-days: 2 - - name: Upload PR Event as Artifact - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - name: preview-spec - path: ${{ github.event_path }} - retention-days: 2 - - delete-preview: - name: Call for Preview Deletion - runs-on: ubuntu-latest - if: ${{ github.event.action == 'closed' }} - steps: - - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 - with: - egress-policy: audit - - # If this PR is closing, we will not render a compose file nor pass it to the next workflow. - - name: Upload PR Event as Artifact - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - name: preview-spec - path: ${{ github.event_path }} - retention-days: 2 diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml deleted file mode 100644 index b4c5aa3caa..0000000000 --- a/.github/workflows/uffizzi-preview.yaml +++ /dev/null @@ -1,238 +0,0 @@ -name: Preview (deploy) - -on: - workflow_run: - workflows: - - 'Preview (build)' - types: - - completed - -jobs: - cache-manifests-file: - name: Cache Manifests File - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} - permissions: - # "If you specify the access for any of these scopes, all of those that are not specified are set to none." - # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions - actions: read # Access cache - outputs: - manifests-cache-key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} - git-ref: ${{ steps.event.outputs.GIT_REF }} - pr-number: ${{ steps.event.outputs.PR_NUMBER }} - action: ${{ steps.event.outputs.ACTION }} - steps: - - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 - with: - disable-sudo: true - egress-policy: block - allowed-endpoints: > - api.github.com:443 - - - name: 'Download artifacts' - # Fetch output (zip archive) from the workflow run that triggered this workflow. - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id, - }); - let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == "preview-spec" - })[0]; - if (matchArtifact === undefined) { - throw TypeError('Build Artifact not found!'); - } - let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', - }); - let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data)); - - - name: 'Accept event from first stage' - run: unzip preview-spec.zip event.json - - - name: Read Event into ENV - id: event - run: | - echo PR_NUMBER=$(jq '.number | tonumber' < event.json) >> $GITHUB_OUTPUT - echo ACTION=$(jq --raw-output '.action | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT - echo GIT_REF=$(jq --raw-output '.pull_request.head.sha | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT - - - name: Hash Rendered Manifests File - id: hash - # If the previous workflow was triggered by a PR close event, we will not have a manifests file artifact. - if: ${{ steps.event.outputs.ACTION != 'closed' }} - run: | - unzip preview-spec.zip manifests.rendered.yml - ls - echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_OUTPUT - - - name: Cache Manifests File - if: ${{ steps.event.outputs.ACTION != 'closed' }} - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: manifests.rendered.yml - key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} - - - name: DEBUG - Print Job Outputs - if: ${{ runner.debug }} - run: | - echo "PR number: ${{ steps.event.outputs.PR_NUMBER }}" - echo "Git Ref: ${{ steps.event.outputs.GIT_REF }}" - echo "Action: ${{ steps.event.outputs.ACTION }}" - echo "Manifests file hash: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }}" - cat event.json - - deploy-uffizzi-preview: - name: Deploy to Uffizzi Virtual Cluster - needs: - - cache-manifests-file - if: ${{ github.event.workflow_run.conclusion == 'success' && needs.cache-manifests-file.outputs.action != 'closed' }} - permissions: - contents: read - pull-requests: write - id-token: write - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - - # Identify comment to be updated - - name: Find comment for Ephemeral Environment - uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3 - id: find-comment - with: - issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} - comment-author: 'github-actions[bot]' - body-includes: pr-${{ needs.cache-manifests-file.outputs.pr-number }} - direction: last - - # Create/Update comment with action deployment status - - name: Create or Update Comment with Deployment Notification - id: notification - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ steps.find-comment.outputs.comment-id }} - issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} - body: | - ## Uffizzi Ephemeral Environment - Virtual Cluster - - :cloud: deploying cluster `pr-${{ needs.cache-manifests-file.outputs.pr-number }}` - - :gear: Updating now by workflow run [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}). - - Download the Uffizzi CLI to interact with the upcoming virtual cluster - https://docs.uffizzi.com/install - edit-mode: replace - - - name: Connect to Virtual Cluster - uses: UffizziCloud/cluster-action@main - with: - cluster-name: pr-${{ needs.cache-manifests-file.outputs.pr-number }} - server: https://app.uffizzi.com - - - name: Fetch cached Manifests File - id: cache - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4 - with: - path: manifests.rendered.yml - key: ${{ needs.cache-manifests-file.outputs.manifests-cache-key }} - - - name: Kustomize and Apply Manifests - id: prev - run: | - # Apply kustomized manifests to virtual cluster. - export KUBECONFIG=`pwd`/kubeconfig - kubectl apply -f manifests.rendered.yml --kubeconfig ./kubeconfig - # Allow uffizzi to sync the resources - sleep 10 - # Get the hostnames assigned by uffizzi - export BACKSTAGE_HOST=$(kubectl get ingress backstage --kubeconfig kubeconfig -o json | jq '.spec.rules[0].host' | tr -d '"') - export UFFIZZI_CLUSTER_APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ") - # Patch backstage deployment to use UFFIZZI_URL - kubectl patch deployment backstage --kubeconfig kubeconfig -p '{"spec": {"template": {"spec": {"containers": [{"name": "backstage", "args":["-c", "APP_CONFIG_app_baseUrl='https://${BACKSTAGE_HOST}' APP_CONFIG_backend_baseUrl='https://${BACKSTAGE_HOST}' APP_CONFIG_auth_environment='production' node packages/backend --config app-config.yaml"], "env": [{"name": "UFFIZZI_URL", "value": "'https://${BACKSTAGE_HOST}'"}, {"name": "UFFIZZI_CLUSTER_APISERVER", "value": "'${UFFIZZI_CLUSTER_APISERVER}'"}, {"name": "GITHUB_SHA", "value": "'${GITHUB_SHA}'"}, {"name": "REF_NAME", "value": "'${{ needs.cache-manifests-file.outputs.git-ref }}'"}]}]}}}}' - if [[ ${RUNNER_DEBUG} == 1 ]]; then - kubectl get all --kubeconfig ./kubeconfig - fi - echo "backstage_url=${BACKSTAGE_HOST}" >> $GITHUB_OUTPUT - echo "Access the \`backstage\` endpoint at [\`${BACKSTAGE_HOST}\`](http://${BACKSTAGE_HOST})" >> $GITHUB_STEP_SUMMARY - - - name: Create or Update Comment with Deployment URL - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ steps.notification.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: | - ## Uffizzi Ephemeral Environment - Virtual Cluster - - Your cluster `pr-${{ needs.cache-manifests-file.outputs.pr-number }}` was successfully created. Learn more about [Uffizzi virtual clusters](https://docs.uffizzi.com/topics/virtual-clusters) - To connect to this cluster, follow these steps: - - 1. Download and install the Uffizzi CLI from https://docs.uffizzi.com/install - 2. Login to Uffizzi, then select the `backstage` account and project: - ``` - uffizzi login - ``` - - ``` - Select an account: - ‣ ${{ github.event.repository.name }} - jdoe - - Select a project or create a new project: - ‣ ${{ github.event.repository.name }}-6783521 - ``` - 3. Update your kubeconfig: `uffizzi cluster update-kubeconfig pr-${{ needs.cache-manifests-file.outputs.pr-number }} --kubeconfig=[PATH_TO_KUBECONFIG]` - After updating your kubeconfig, you can manage your cluster with `kubectl`, `kustomize`, `helm`, and other tools that use kubeconfig files: `kubectl get namespace --kubeconfig [PATH_TO_KUBECONFIG]` - - - Access the `backstage` endpoint at [`https://${{ steps.prev.outputs.backstage_url }}`](https://${{ steps.prev.outputs.backstage_url }}) - - edit-mode: replace - - delete-uffizzi-preview: - permissions: - contents: read - pull-requests: write - id-token: write - name: Delete the Uffizzi Virtual Cluster - needs: - - cache-manifests-file - if: ${{ needs.cache-manifests-file.outputs.action == 'closed' }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - - - name: Delete Virtual Cluster - uses: UffizziCloud/cluster-action@main - with: - cluster-name: pr-${{ needs.cache-manifests-file.outputs.pr-number }} - server: https://app.uffizzi.com - action: delete - - # Identify comment to be updated - - name: Find comment for Ephemeral Environment - uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3 - id: find-comment - with: - issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} - comment-author: 'github-actions[bot]' - body-includes: pr-${{ needs.cache-manifests-file.outputs.pr-number }} - direction: last - - - name: Update Comment with Deletion - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ steps.find-comment.outputs.comment-id }} - issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} - body: | - Uffizzi Cluster `pr-${{ needs.cache-manifests-file.outputs.pr-number }}` was deleted. - edit-mode: replace diff --git a/.github/workflows/verify_accessibility-noop.yml b/.github/workflows/verify_accessibility-noop.yml index 07c92b5b5d..7ec67cbf0f 100644 --- a/.github/workflows/verify_accessibility-noop.yml +++ b/.github/workflows/verify_accessibility-noop.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/verify_accessibility.yml b/.github/workflows/verify_accessibility.yml index 1c25d709cb..996153f8d3 100644 --- a/.github/workflows/verify_accessibility.yml +++ b/.github/workflows/verify_accessibility.yml @@ -20,11 +20,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Use Node.js 18.x uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 with: diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index e82577763e..bcac7e947c 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -42,12 +42,12 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - name: Checkout repository - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/init@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/autobuild@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -80,4 +80,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/analyze@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 diff --git a/.github/workflows/verify_docs-quality.yml b/.github/workflows/verify_docs-quality.yml index 3550df6fc0..5b213f2c14 100644 --- a/.github/workflows/verify_docs-quality.yml +++ b/.github/workflows/verify_docs-quality.yml @@ -12,11 +12,11 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 # Vale does not support file excludes, so we use the script to generate a list of files instead # The action also does not allow args or a local config file to be passed in, so the files array diff --git a/.github/workflows/verify_e2e-kubernetes-noop.yml b/.github/workflows/verify_e2e-kubernetes-noop.yml index 8d8b14d5ba..6352abce70 100644 --- a/.github/workflows/verify_e2e-kubernetes-noop.yml +++ b/.github/workflows/verify_e2e-kubernetes-noop.yml @@ -23,7 +23,7 @@ jobs: name: Kubernetes ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-kubernetes.yml b/.github/workflows/verify_e2e-kubernetes.yml index 6ff41c8b74..77d2c3bdc1 100644 --- a/.github/workflows/verify_e2e-kubernetes.yml +++ b/.github/workflows/verify_e2e-kubernetes.yml @@ -22,11 +22,11 @@ jobs: name: Kubernetes ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.github/workflows/verify_e2e-linux-noop.yml b/.github/workflows/verify_e2e-linux-noop.yml index 93d48caf22..2b7eb1d84b 100644 --- a/.github/workflows/verify_e2e-linux-noop.yml +++ b/.github/workflows/verify_e2e-linux-noop.yml @@ -29,7 +29,7 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index a750dfea3b..f8583ac178 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -41,11 +41,11 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Configure Git run: | diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml index 3bcda5f2b6..2ed566e36b 100644 --- a/.github/workflows/verify_e2e-techdocs.yml +++ b/.github/workflows/verify_e2e-techdocs.yml @@ -30,11 +30,11 @@ jobs: name: Techdocs steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: python-version: '3.9' diff --git a/.github/workflows/verify_e2e-windows-noop.yml b/.github/workflows/verify_e2e-windows-noop.yml index a7ebdba4b5..fd90b86b0d 100644 --- a/.github/workflows/verify_e2e-windows-noop.yml +++ b/.github/workflows/verify_e2e-windows-noop.yml @@ -25,7 +25,7 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml index 078ddd6855..e2a789d666 100644 --- a/.github/workflows/verify_e2e-windows.yml +++ b/.github/workflows/verify_e2e-windows.yml @@ -31,7 +31,7 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit @@ -42,7 +42,7 @@ jobs: git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Configure Git run: | diff --git a/.github/workflows/verify_fossa.yml b/.github/workflows/verify_fossa.yml index 801c5fbd28..ba5d177cc4 100644 --- a/.github/workflows/verify_fossa.yml +++ b/.github/workflows/verify_fossa.yml @@ -14,12 +14,12 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - name: Checkout - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Install Fossa run: "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | bash" diff --git a/.github/workflows/verify_microsite-noop.yml b/.github/workflows/verify_microsite-noop.yml index ad3e67ba70..a9a82b140b 100644 --- a/.github/workflows/verify_microsite-noop.yml +++ b/.github/workflows/verify_microsite-noop.yml @@ -21,7 +21,7 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index 68378aa086..256b00b160 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -24,17 +24,17 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js 18.x uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 with: node-version: 18.x - - uses: actions/setup-python@v5 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: python-version: '3.9' diff --git a/.github/workflows/verify_microsite_accessibility-noop.yml b/.github/workflows/verify_microsite_accessibility-noop.yml index 4b63dc41cc..8ac2672b22 100644 --- a/.github/workflows/verify_microsite_accessibility-noop.yml +++ b/.github/workflows/verify_microsite_accessibility-noop.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite_accessibility.yml b/.github/workflows/verify_microsite_accessibility.yml index e0fea1a72c..9986ae051e 100644 --- a/.github/workflows/verify_microsite_accessibility.yml +++ b/.github/workflows/verify_microsite_accessibility.yml @@ -15,11 +15,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Use Node.js 18.x uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.github/workflows/verify_storybook-noop.yml b/.github/workflows/verify_storybook-noop.yml index 74aed57f5c..e98da4ae02 100644 --- a/.github/workflows/verify_storybook-noop.yml +++ b/.github/workflows/verify_storybook-noop.yml @@ -28,7 +28,7 @@ jobs: name: Storybook steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 940c136797..1859c0b8bc 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -28,11 +28,11 @@ jobs: name: Storybook steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: fetch-depth: 0 # Required to retrieve git history diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index 32b0452eec..5c4bed2d11 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -29,11 +29,11 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 with: egress-policy: audit - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.yarn/patches/@changesets-assemble-release-plan-npm-6.0.0-f7b3005037.patch b/.yarn/patches/@changesets-assemble-release-plan-npm-6.0.0-f7b3005037.patch new file mode 100644 index 0000000000..045e983dbe --- /dev/null +++ b/.yarn/patches/@changesets-assemble-release-plan-npm-6.0.0-f7b3005037.patch @@ -0,0 +1,32 @@ +diff --git a/dist/changesets-assemble-release-plan.cjs.js b/dist/changesets-assemble-release-plan.cjs.js +index ee5c0f67fabadeb112e9f238d8b144a4d125830f..9b0e1a156dd88cee35f82faf718d82a8a8f80325 100644 +--- a/dist/changesets-assemble-release-plan.cjs.js ++++ b/dist/changesets-assemble-release-plan.cjs.js +@@ -179,12 +179,23 @@ function getDependencyVersionRanges(dependentPkgJSON, dependencyRelease) { + if (!versionRange) continue; + + if (versionRange.startsWith("workspace:")) { ++ // intentionally keep other workspace ranges untouched ++ // this has to be fixed but this should only be done when adding appropriate tests ++ let workspaceRange = versionRange.replace(/^workspace:/, ""); ++ switch (workspaceRange) { ++ case "*": ++ // workspace:* actually means the current exact version, and not a wildcard similar to a reguler * range ++ workspaceRange = dependencyRelease.oldVersion; ++ break; ++ case "~": ++ case "^": ++ // Use ^oldVersion for workspace:^ or ~oldVersion for workspace:~. ++ // The version range might have changed in dependent package, but that should have its own changeset bumping that package. ++ workspaceRange += dependencyRelease.oldVersion; ++ } + dependencyVersionRanges.push({ + depType: type, +- versionRange: // intentionally keep other workspace ranges untouched +- // this has to be fixed but this should only be done when adding appropriate tests +- versionRange === "workspace:*" ? // workspace:* actually means the current exact version, and not a wildcard similar to a reguler * range +- dependencyRelease.oldVersion : versionRange.replace(/^workspace:/, "") ++ versionRange: workspaceRange, + }); + } else { + dependencyVersionRanges.push({ diff --git a/ADOPTERS.md b/ADOPTERS.md index 3878563683..2bb76a199e 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -154,7 +154,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Lendingkart](https://www.lendingkart.com/) | [Dinesh Rajpoot](mailto:dinesh.rajpoot@lendingkart.com) | Service catalog, Software templates to enforce best practices and tech insights to track mandates & migrations. | | [Meltwater](https://underthehood.meltwater.com) | [@spier](https://github.com/spier), [@remen](https://github.com/remen) | Improving developer experience by centralizing documentation and internal APIs. Goal: Foster InnerSource collaboration and speed up onboarding time in our 500+ people Product & Engineering org. | | [Doctolib](https://doctolib.engineering/) | [@djiit](https://github.com/djiit) | Rails modularization effort awareness, tech organization discoverability. Improving the daily workflows and collaboration processes of our engineers. | -| [Twilio](https://www.twilio.com) | [Kyle Smith](https://github.com/knksmith57) | Developer portal, universal software catalog, and centralized taxonomy platform. | +| [Twilio](https://www.twilio.com) | [Alec Jacobs](https://github.com/alecjacobs5401) | Developer portal, universal software catalog, and centralized taxonomy platform. | | [OVHcloud](https://www.ovhcloud.com/fr/) | [Jean-Philippe Blary](https://github.com/blaryjp), [Arnaud Bauer](mailto:arnaud.bauer@ovhcloud.com), [Flavien Chantelot](https://github.com/Dorn-) | We're providing Backstage to our collaborators to ease their daily jobs, and let them extends it using plugins. | | [Procter & Gamble](https://us.pg.com/) | [Binita Nayak](https://github.com/binitan), | P&G leverages Backstage to build internal developer portal to ensure developers' happiness. This developer portal shall act as single source of information needed by development teams to seamlessly create, find and maintain their software components/resources/documentation. | | [SANS Institute](https://www.sans.org) | [Christopher Klewin](mailto:cklewin@sans.org) | Developer portal for centralized visibility, reporting, and tooling across multiple organizations. | @@ -268,3 +268,5 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Aurora Innovation](https://aurorainnovation.com) | [@O5ten](https://github.com/O5ten) | Heavy usage of scaffolder, techdocs, homepage, k8s plugin and homegrown plugins to track migration paths and so on within a developer portal. It acts as a starting point for new and old developers to find all of our internal tooling in one place. | [ENSEK](https://ensek.com/) | [Timothy Deakin](https://github.com/cftad) |We are using Backstage as our internal developer portal to provide a single pane of glass for our developers to access all the tools and services they need to build and maintain our software. | | [OP Financial Group](https://www.op.fi/op-financial-group) | [Heikki Hellgren](https://github.com/drodil), [Jyrki Koistinen](https://github.com/snyvision) | We are using Backstage as a gateway into our internal development platform offering to simplify complexity. | +| [Scania](https://www.scania.com) | [Santosh Rangavajjula](https://linkedin.com/in/rsbth) | We are implementing backstage at Scania to consolidate operational information from Gitlab, Jira, Confluence, Artifactory, Servicenow and other tools into one place. | +| [Senora.dev](https://senora.dev) | [Shaked Braimok Yosef](https://github.com/ShakedBraimok) | We are using Backstage as a service catalog for our costumers. | diff --git a/GOVERNANCE.md b/GOVERNANCE.md deleted file mode 100644 index 2367dab99c..0000000000 --- a/GOVERNANCE.md +++ /dev/null @@ -1,233 +0,0 @@ -# Project Areas - -The Backstage project is divided into several project areas, each covering particular parts of the project. The main driver for each area is ownership of code in the main Backstage repository, as well as other repositories in the Backstage GitHub organization. Each area has a set of maintainers and repository content that they own. There may be no overlap in ownership between areas, which means that any given line in the GitHub code owners file should have only one owner specified. Each area is represented by a team in the Backstage GitHub organization. Apart from certain project-wide concerns, such as the release process, each area is self-governing and chooses their own ways of working. Project areas may also have special interest groups (SIGs) related to their area, but this is not required. - -The project areas as well as their maintainers are listed in the [OWNERS.md](./OWNERS.md) file. - -Each project area must have at least one maintainer. Project area maintainers may have shared ownership with the core maintainers, which in that case is considered an incubating area. The project area maintainers help drive work forward in the area, but they might not yet feel ready to take on ownership. The goal should generally be that these project area maintainers eventually become sole maintainers of the project area. This is to allow for a more smooth onboarding and transition of ownership, where members of the community might for example be new to open source maintainership. - -## Adding new project areas - -Project areas are added by nominating new maintainers for that area. See the sections for becoming a [Project Area Maintainer](#project-area-maintainer). - -Project areas may also by added by splitting existing areas. Every area that is created through this process must have at least one maintainer. - -## Removing project areas - -Project areas are removed by removing all maintainers for that area and removing the corresponding team from the Backstage GitHub organization. The project area can be re-added later if there is a need for it. Reasons for removal may include lack of activity, lack of maintainers, or lack of relevance to the project. - -# Project Roles - -## Contributor - -A Contributor contributes directly to the project and adds value to it. Contributions need not be code. People at the Contributor level may be new contributors, or they may only contribute occasionally. - -### Responsibilities - -- Follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) -- Follow the project [contributing guide](CONTRIBUTING.md) - -### How to get involved - -- Participate in community discussions -- Help other users -- Submit bug reports -- Comment on issues -- Try out new releases -- Attend community events - -### How to contribute - -- Report and sometimes resolve issues -- Occasionally submit PRs -- Contribute to the documentation -- Show up at meetings, take notes -- Answer questions from other community members -- Submit feedback on issues and PRs -- Test releases and patches and submit reviews -- Run or help run events -- Promote the project in public - -## Organization Member - -An org member is a frequent contributor that has become a member of the Backstage GitHub organization. In addition to the responsibilities of contributors, an org member is also expected to be reasonably active in the community through continuous contributions of any type. - -An Organization Member must meet the responsibilities and has the requirements of a Contributor. - -### Responsibilities - -- Continues to contribute regularly, as demonstrated by having at least 10 GitHub contributions per year in [Devstats](https://backstage.devstats.cncf.io/d/48/users-statistics-by-repository-group?orgId=1&var-period=y&var-metric=contributions&var-repogroup_name=All&from=now-1y&to=now&var-users=All), or contributions of a similar effort that might not be captured in Devstats. - -### Requirements - -- Must have at least 10 contributions to the projects in the form of: - - Accepted PRs - - Helpful PR reviews - - Resolving GitHub issues - - Or some equivalent contributions to the project -- Must have been contributing for at least 3 months -- Or is the member of a team that owns a project area, in which case the above requirements do not apply and the member is instead vetted by the project area maintainers - -### Becoming an Organization Member - -Open an issue towards [the community repository](https://github.com/backstage/community) using the [org membership request template](https://github.com/backstage/community/issues/new?template=org_member.yaml&title=Org+Member%3A+%3Cyour-github-login%3E). - -### Privileges - -- Membership in the Backstage GitHub organization - -## Plugin Maintainer - -A Plugin Maintainer is responsible for maintaining an individual Backstage plugin or module. This includes reviewing contributions and responding to issues towards an individual plugin, as well as keeping the plugin up to date. - -Plugin Maintainer is a lightweight form of ownership that is primarily reflected though code owners of the plugin packages in the [CODEOWNERS](./.github/CODEOWNERS) file. Each plugin can have one or more maintainers. If a plugin becomes a significant part of the Backstage ecosystem, it may be promoted to be a distinct project area instead. - -A Plugin Maintainer has all the rights and responsibilities of an Organization Member. - -### Responsibilities - -- Review the majority of PRs towards the plugin -- Respond to GitHub issues related to the plugin -- Keep the plugin up-to-date with Backstage libraries and other dependencies -- Follow the [reviewing guide](REVIEWING.md) - -### Requirements - -- Is an Organization Member -- Display knowledge of Backstage's review process and best practices for plugin design -- Is supportive of new and occasional contributors and helps get useful PRs in shape to merge - -### Privileges - -- GitHub code owner of the plugin directory, with rights to approve and merge PRs towards the plugin - -### Becoming a Plugin Maintainer - -To become a Plugin Maintainer, you first need to be an Organization Member. You can then file a pull request towards [CODEOWNERS.md](./.github/CODEOWNERS) requesting to be added as a code owner of the plugin directory. Existing code owners of that plugin alongside the core maintainers will then review the request. - -## Project Area Maintainer - -Project Area Maintainers are owners of a particular project area. They are expected to review and merge pull requests towards their area, and also drive development and manage tech health. A Project Area Maintainer also need to commit a certain number of hours per month towards the project, and exercise judgment for the good of the project, independent of their employer. Project Area Maintainers should also mentor new maintainers and participate in and lead community meetings related to their area. New Project Area Maintainers need to be approved by the existing project area maintainers, or the core maintainers if it is a new area. - -The maintainers of a project area may be represented by a team in external organization. In this case, the state as a project area maintainer is tied to the membership in that team. New members of the team may automatically be added as maintainers, as well as removed when they leave. This process is governed autonomously by the team of project area maintainers. - -A Project Area Maintainer has all the rights and responsibilities of an Organization Member. - -### Responsibilities - -- Review PRs towards their project area. Project area maintainers are expected to review at least 20 PRs per year, or the majority of all PRs towards the area, if it is less than 20 -- Follow the [reviewing guide](REVIEWING.md) -- Triage and respond to issues related to their project area -- Mentor new project area maintainers -- Write refactoring PRs -- Determine strategy and policy for the project area -- Participate in or leading community meetings related to their project area - -### Requirements - -- Is an Organization Member -- Have made at least 5 meaningful contributions towards the project area -- Demonstrates knowledge of their project area, and how it fits into the larger Backstage project -- Is able to exercise judgment for the good of the project, independent of their employer, friends, or team -- Mentors other contributors and project area maintainers -- Can commit to spending at least 16 hours per month working on the project, preferably distributed evenly across the month - -### Privileges - -- Approve and merge PRs towards their project area -- Drive the direction and roadmap of their project area - -### Becoming a Project Area Maintainer - -If you are interested in becoming a project area maintainer, reach out to the existing maintainers for that area. If you wish to become a maintainer for a new area, reach out to the core maintainers. - -Any current project area maintainer or core maintainer may nominate a new project area maintainer by opening a PR towards the [OWNERS.md](OWNERS.md) file. A majority of the project area maintainers for that area must approve the PR. If there are no existing maintainers for that area, the PR must be approved by a majority of the core maintainers. - -## Core Maintainer - -Core Maintainers are responsible for the Backstage project as a whole. They help review and merge project-level pull requests as well as coordinate work affecting multiple project areas. A core maintainer needs to commit the majority of their working time towards the project, and exercise judgment for the good of the project, independent of their employer. Core maintainers should also mentor and seek out new maintainers, lead community meetings, and communicate with the CNCF on behalf of the project. To become a core maintainer one needs to have been the maintainer of a number of different project areas, demonstrate a deep knowledge of large parts of the Backstage project, and be backed by the existing core maintainers. - -A Core Maintainer have all the rights and responsibilities of a Project Area Maintainer. - -### Responsibilities - -- Take part in the incoming issue and PR triage and review process. PRs are shared equally among all maintainers -- Mentor new Project Area Maintainers and Plugin Maintainers -- Drive refactoring and manage tech health across the entire project -- Participate in CNCF maintainer activities -- Respond to security incidents in accordance to our [security policy](./SECURITY.md) -- Determine strategy and policy for the project -- Participate in or leading community meetings - -### Requirements - -- Experience as a Project Area Maintainer for at least 6 months -- Demonstrates a broad knowledge of the project across multiple areas -- Is able to exercise judgment for the good of the project, independent of their employer, friends, or team -- Mentors other contributors -- Can commit to spending at least 10 days per month working on the project - -### Privileges - -- Approve PRs that fall outside any specific project area -- Merge PRs to any area of the project -- Represent the project in public as a Maintainer -- Communicate with the CNCF on behalf of the project -- Have a vote in Maintainer decision-making meetings - -### Becoming a Core Maintainer - -Any core maintainer or end user sponsor may nominate a new core maintainer by opening a PR towards the [OWNERS.md](OWNERS.md) file. Core maintainers must be approved by a majority of the existing core maintainers and end user sponsors. - -## End User Sponsors - -### Role of a Backstage End User Sponsor - -- Provide support for Backstage by removing blockers, securing funding, providing advocacy, feedback, and ensuring project continuity and long term success -- Assist Backstage maintainers in prioritizing upcoming roadmap items and planned work -- Provide neutral mediation for any disputes that arise as part of the project - -### Backstage End User Sponsor Membership - -The End User Sponsors group comprises at most 5 people. To be eligible for membership in the group, you or the company where you work you must: - -- Be responsible for and end user of a production Backstage deployment of non-trivial size -- Be active contributors to the open source project -- Be willing and able to attend regularly-scheduled End User Sponsor meetings -- Abide by [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) - -Candidates for membership will be nominated by current Sponsor members or by Backstage maintainers. If there are more nominations than Sponsor seats remaining, existing sponsors shall vote on the candidates, and the candidates with the most votes will become Sponsors. Any ties will be broken by current Backstage sponsors. - -# Conflict resolution and voting - -In general, we prefer that technical issues and membership are amicably worked out between the persons involved. If a dispute cannot be decided independently, the sponsors and core maintainers can be called in to decide an issue. If the sponsors and maintainers themselves cannot decide an issue, the issue will be resolved by voting. - -In all cases in this document where voting is mentioned, the voting process is a simple majority in which each sponsor receives two votes and each core maintainer receives one vote. If such a majority is reached, the vote is said to have _passed_. - -## Inactivity - -It is important for contributors to be and stay active to set an example and show commitment to the project. Inactivity is harmful to the project as it may lead to unexpected delays, contributor attrition, and a loss of trust in the project. - -Inactivity is measured by periods of no contributions without explanation, for longer than: - -- Core Maintainer: 2 months -- Project Area Maintainer: 4 months -- Plugin Maintainer: 6 months -- Organization Member: 12 months - -Consequences of being inactive include: - -- Involuntary removal or demotion -- Being asked to move to Emeritus status - -## Involuntary Removal or Demotion - -Involuntary removal/demotion of a contributor happens when responsibilities and requirements aren't being met. This may include repeated patterns of inactivity, extended period of inactivity, a period of failing to meet the requirements of your role, and/or a violation of the Code of Conduct. This process is important because it protects the community and its deliverables while also opens up opportunities for new contributors to step in. - -Involuntary removal or demotion is handled through a vote by a majority of the current Core Maintainers. Some aspects of this process may be automated, such as removal after periods of inactivity. - -## Stepping Down/Emeritus Process - -If and when contributors' commitment levels change, contributors can consider stepping down (moving down the contributor ladder) vs moving to emeritus status (completely stepping away from the project). - -Contact the Maintainers about changing to Emeritus status, or reducing your contributor level. diff --git a/NOTICE b/NOTICE index fb23d28ebc..1f1dfbccbb 100644 --- a/NOTICE +++ b/NOTICE @@ -5,3 +5,4 @@ Portions of this software were developed by third-party software vendors: - Tech Radar Plugin (https://opensource.zalando.com/tech-radar/), Copyright (c) 2017 Zalando SE - [OpenAPI Generator Templates](./packages/repo-tools/templates), Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) Copyright 2018 SmartBear Software +- Optic CLI (https://github.com/opticdev/optic), Copyright 2022, Optic Labs Corporation diff --git a/OWNERS.md b/OWNERS.md index ab35b5b1e5..bf97c91685 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -1,5 +1,5 @@ - See [CONTRIBUTING.md](CONTRIBUTING.md) for general contribution guidelines. -- See [GOVERNANCE.md](GOVERNANCE.md) for governance guidelines and responsibilities. +- See [GOVERNANCE.md](https://github.com/backstage/community/blob/main/GOVERNANCE.md) for governance guidelines and responsibilities. ## Core Maintainers @@ -22,14 +22,15 @@ Team: @backstage/catalog-maintainers Scope: The catalog plugin and catalog model -| Name | Organization | Team | GitHub | Discord | -| --------------- | ------------ | --------- | ----------------------------------------- | ------------------- | -| Rickard Dybeck | Spotify | Chipmunks | [alde](https://github.com/alde) | `rdybeck#8083` | -| Mike Blockley | Spotify | Chipmunks | [mikeyhc](https://github.com/mikeyhc) | `mikey-spot#5363` | -| Elon Jefferson | Spotify | Chipmunks | [Edje-C](https://github.com/Edje-C) | `elon-spotty#6086 ` | -| Nurit Izrailov | Spotify | Chipmunks | [nuritizra](https://github.com/nuritizra) | - | -| Hunter Dougless | Spotify | Chipmunks | [hntrdglss](https://github.com/hntrdglss) | `hntrdglss#1849` | -| Seve Kim | Spotify | Chipmunks | [sevedkim](https://github.com/sevedkim) | `seve#9951` | +| Name | Organization | Team | GitHub | Discord | +| -------------------- | ------------ | ------------- | ----------------------------------------------- | --------------- | +| Ben Lambert | Spotify | Cubic Belugas | [benjdlambert](https://github.com/benjdlambert) | `blam#2159` | +| Camila Loiola | Spotify | Cubic Belugas | [camilaibs](http://github.com/camilaibs) | `camilal#0226` | +| Fredrik Adelöw | Spotify | Cubic Belugas | [freben](https://github.com/freben) | `freben#3926` | +| Johan Haals | Spotify | Cubic Belugas | [jhaals](https://github.com/jhaals) | `Johan#0679` | +| Mihai Tabara | Spotify | Cubic Belugas | [MihaiTabara](http://github.com/MihaiTabara) | `mihait#3107` | +| Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip#0019` | +| Vincenzo Scamporlino | Spotify | Cubic Belugas | [vinzscam](http://github.com/vinzscam) | `vinzscam#6944` | ### Discoverability @@ -73,14 +74,15 @@ Team: @backstage/permission-maintainers Scope: The Permission Framework and plugins integrating with the permission framework -| Name | Organization | Team | GitHub | Discord | -| -------------------- | ------------ | --------------- | ------------------------------------------ | ------------- | -| Ainhoa Larumbe | Spotify | Imaginary Goats | [ainhoaL](http://github.com/ainhoaL) | ainhoa#8085 | -| Eric Peterson | Spotify | Imaginary Goats | [iamEAP](http://github.com/iamEAP) | iamEAP#3058 | -| Harry Hogg | Spotify | Imaginary Goats | [HHogg](http://github.com/HHogg) | simplex#3451 | -| Joon Park | Spotify | Imaginary Goats | [Joonpark13](http://github.com/Joonpark13) | Sixpool#5060 | -| Mike Lewis | Spotify | Imaginary Goats | [mtlewis](http://github.com/mtlewis) | mtlewis#3658 | -| Vincenzo Scamporlino | Spotify | Imaginary Goats | [vinzscam](http://github.com/vinzscam) | vinzscam#6944 | +| Name | Organization | Team | GitHub | Discord | +| -------------------- | ------------ | ------------- | ----------------------------------------------- | --------------- | +| Ben Lambert | Spotify | Cubic Belugas | [benjdlambert](https://github.com/benjdlambert) | `blam#2159` | +| Camila Loiola | Spotify | Cubic Belugas | [camilaibs](http://github.com/camilaibs) | `camilal#0226` | +| Fredrik Adelöw | Spotify | Cubic Belugas | [freben](https://github.com/freben) | `freben#3926` | +| Johan Haals | Spotify | Cubic Belugas | [jhaals](https://github.com/jhaals) | `Johan#0679` | +| Mihai Tabara | Spotify | Cubic Belugas | [MihaiTabara](http://github.com/MihaiTabara) | `mihait#3107` | +| Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip#0019` | +| Vincenzo Scamporlino | Spotify | Cubic Belugas | [vinzscam](http://github.com/vinzscam) | `vinzscam#6944` | ### TechDocs @@ -187,6 +189,7 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling. | Miklós Kiss | Roadie.io | [kissmikijr](https://github.com/kissmikijr) | `Miklos#7416` | | Patrick Jungermann | Bonial International GmbH | [pjungermann](https://github.com/pjungermann) | `pjungermann#6933` | | Phil Kuang | FactSet Research Systems | [kuangp](https://github.com/kuangp) | `pkuang#3202` | +| Sebastian Poxhofer | N26 | [secustor](https://github.com/secustor) | `secustor` | | Taras Mankovski | Frontside | [taras](https://github.com/taras) | `tarasm#1256` | ## Emeritus Core Maintainers diff --git a/README-ko_kr.md b/README-ko_kr.md index e5f50bd2b8..b2bba41567 100644 --- a/README-ko_kr.md +++ b/README-ko_kr.md @@ -10,7 +10,6 @@ ![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) [![Codecov](https://img.shields.io/codecov/c/github/backstage/backstage)](https://codecov.io/gh/backstage/backstage) [![](https://img.shields.io/github/v/release/backstage/backstage)](https://github.com/backstage/backstage/releases) -[![Uffizzi](https://img.shields.io/endpoint?url=https%3A%2F%2Fapp.uffizzi.com%2Fapi%2Fv1%2Fpublic%2Fshields%2Fgithub.com%2Fbackstage%2Fbackstage)](https://app.uffizzi.com/ephemeral-environments/backstage/backstage) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7678/badge)](https://bestpractices.coreinfrastructure.org/projects/7678) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/backstage/backstage/badge)](https://securityscorecards.dev/viewer/?uri=github.com/backstage/backstage) diff --git a/README-zh_Hans.md b/README-zh_Hans.md index 3e6cea4e95..2813ee0793 100644 --- a/README-zh_Hans.md +++ b/README-zh_Hans.md @@ -10,7 +10,6 @@ ![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) [![Codecov](https://img.shields.io/codecov/c/github/backstage/backstage)](https://codecov.io/gh/backstage/backstage) [![](https://img.shields.io/github/v/release/backstage/backstage)](https://github.com/backstage/backstage/releases) -[![Uffizzi](https://img.shields.io/endpoint?url=https%3A%2F%2Fapp.uffizzi.com%2Fapi%2Fv1%2Fpublic%2Fshields%2Fgithub.com%2Fbackstage%2Fbackstage)](https://app.uffizzi.com/ephemeral-environments/backstage/backstage) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7678/badge)](https://bestpractices.coreinfrastructure.org/projects/7678) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/backstage/backstage/badge)](https://securityscorecards.dev/viewer/?uri=github.com/backstage/backstage) diff --git a/README.md b/README.md index 6cea4235e0..47ae539b6b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ English \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) ![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) [![Codecov](https://img.shields.io/codecov/c/github/backstage/backstage)](https://codecov.io/gh/backstage/backstage) [![](https://img.shields.io/github/v/release/backstage/backstage)](https://github.com/backstage/backstage/releases) -[![Uffizzi](https://img.shields.io/endpoint?url=https%3A%2F%2Fapp.uffizzi.com%2Fapi%2Fv1%2Fpublic%2Fshields%2Fgithub.com%2Fbackstage%2Fbackstage)](https://app.uffizzi.com/ephemeral-environments/backstage/backstage) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7678/badge)](https://bestpractices.coreinfrastructure.org/projects/7678) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/backstage/backstage/badge)](https://securityscorecards.dev/viewer/?uri=github.com/backstage/backstage) diff --git a/SECURITY.md b/SECURITY.md index 5866fff2b4..8de1307356 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -66,7 +66,7 @@ The insecure example above should instead be written like this: ```ts // THIS IS GOOD, DO THIS -import { resolveSafeChildPath } from '@backstaghe/backend-common'; +import { resolveSafeChildPath } from '@backstage/backend-common'; import fs from 'fs-extra'; function writeTemporaryFile(tmpDir: string, name: string, content: string) { diff --git a/app-config.yaml b/app-config.yaml index 9e5b5c468c..cb70170541 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -9,6 +9,9 @@ app: # applicationId: qwerty # site: # datadoghq.eu default = datadoghq.com # env: # optional + # sessionSampleRate: 100 + # sessionReplaySampleRate: 0 + support: url: https://github.com/backstage/backstage/issues # Used by common ErrorPage items: # Used by common SupportButton component diff --git a/beps/0001-notifications-system/README.md b/beps/0001-notifications-system/README.md index 4b4f3b0532..80751179dd 100644 --- a/beps/0001-notifications-system/README.md +++ b/beps/0001-notifications-system/README.md @@ -92,7 +92,7 @@ If the notification status is updated, the signal service shall emit a signal wi The role of the notifications plugin is to manage the lifecycle of notifications. The backend plugin provides an API for other backends to send notifications, as well as an accompanying [backend service](https://backstage.io/docs/backend-system/architecture/services). It also provides a separate API for the frontend plugin to read notifications for an individual user and manage the read status of notifications. -The notification backend stores notification using the [database service](https://backstage.io/docs/backend-system/core-services/index#database). In particular it needs to store the following information for each notification: +The notification backend stores notification using the [database service](https://backstage.io/docs/backend-system/core-services/index#database). In particular, it needs to store the following information for each notification: - ID - Recipients @@ -110,8 +110,9 @@ The notification backend stores notification using the [database service](https: - Topic (optional) - Scope (optional) - Icon (optional) + - Metadata (optional) -The recipients is **not** a list of users, but rather a filter that describes who should receive the notification. It must be possible to evaluate this filter in a database query, so that we can efficiently fetch all notifications for a given user. The same filter will also be used by the signal backend to determine which users should receive a signal. +The recipients are **not** a list of users, but rather a filter that describes who should receive the notification. It must be possible to evaluate this filter in a database query, so that we can efficiently fetch all notifications for a given user. The same filter will also be used by the signal backend to determine which users should receive a signal. The read date is a timestamp of marking the notifications as read by the user. If missing, the notification is still unread. @@ -147,6 +148,8 @@ The link is a relative or absolute URL. As an example, it can be used: - by an external system to request an action within an asynchronous task - by a BE plugin to provide link to other part of the Backstage UI (i.e. to the Catalog) +The metadata is an opaque JSON field, where an additional payload can be stored. The format of this data is owned by the notification sender and is tied to the notification topic, i.e. notifications sent from the source on the same topic should use a compatible metadata format. The primary purpose of this field is to allow for custom processing and rendering based on the additional metadata. + The additional links are an array of title-URL pairs. They can represent immediate actions on the notification (i.e. yes-no) or lead the user to additional details. The `notification-backend` does not provide any new permissions, since creating notifications can only be done by other backend plugins, while reading notifications can only be done by the authenticated user. It is possible that we want to add a permissions for reading notifications, in particular for admin and impersonation use cases, but that is not part of this proposal or the initial implementation. @@ -206,12 +209,16 @@ export type NotificationSeverity = 'critical' | 'high' | 'normal' | 'low'; export type NotificationPayload = { title: string; description?: string; - link: string; + link?: string; additionalLinks?: string[]; - severity: NotificationSeverity; + severity?: NotificationSeverity; topic?: string; scope?: string; icon?: string; + metadata?: Array<{ + type: string; + value: JsonValue; + }>; }; export type Notification = { @@ -236,7 +243,8 @@ interface NotificationService { } ``` -Each notification contains a human readable `title`, `origin` and optionally `link` for additional details. The `created`, `id`, `read` and `saved` properties are handled by the backend based and cannot be passed during the notification creation. +Each notification contains a human-readable `title`, `origin` and optionally `link` for additional details. The `created`, `id`, `read` and `saved` properties are handled by the backend based and cannot be passed during the notification creation. +Any optional additional details could be stored in `metadata`. We advise to provide the name to the type which contains the information about the context and the version, for example: 'core.icon.v1'. Calling `sendNotification` should never throw an error so that it doesn't block the current processing. Notifications should be considered as second-level citizens that are not critical if not delivered. @@ -380,10 +388,39 @@ interface SignalApi { - Render dynamic values with various different React elements such as the `EntityRefLink` for entity references (for example `{{ user:default/john.doe }}`) in the notification payload - Handle `link` values that use route references. For example instead hard-coding link to `/catalog/default/component/artist-web` it should be possible to use `catalogPlugin.catalogEntity` route reference as a link of the notification. This should also allow using parameters to be passed to the route reference. Links to external systems are still supported. - Add support for `analyticsApi` to notification actions like marking notifications done, saved or opening links in the notifications -- Add support for user settings to control how notifications are shown to the user and which notifications user wants to receive. This should also include support for different `NotificationProcessor`s that can send notification to external systems - Add a sound to be played when notification is received - Add i18n internationalization support for the notification payload +### User specific notification settings + +To allow the users more fine-grained control of notifications, user must have an option to unsubscribe from specific origins, topics and channels. + +By default, all notifications are enabled for the user in all notification channels. Frontend plugin provides an user interface to change these settings for example as described in the following image: + +![user notification settings UI example](./UserNotificationSettings.png) + +Each notification processor with `send` functionality will be listed as a separate channel among the Backstage internal notification channel `Web`. For this, each notification processor must implement a function to get a human readable name to be rendered in the frontend. + +User must be able to save these settings to the notification database, and they are be checked each time a new notification is sent to the user. + +Disabling a notification from specific origin or topic in the `Web` channel will not remove the old notifications being visible in the frontend from that source but instead, it only prevents new notifications being sent. + +For performance reasons the notification settings will ignore all broadcast notifications and those will be sent to all users despite their origin or channel. + +```ts +export type NotificationSetting = { + origin: string; + topic?: string; + channels: Record; +}; + +export type UserNotificationSettings = { + settings: NotificationSetting[]; +}; +``` + +The backend plugin returns user notification settings for all known origins, topics and channels it knows of. As new origins, topics and channels will get added, also the notification settings list will get longer. This allows an easy way to add new notification origins, topics and channels without need to change the notification plugin. If the user is missing notification setting from specific origin/topic/channel, the backend considers it as enabled. + ## Release Plan The notification and signal plugins are released as two new plugins in the Backstage ecosystem. They will both start out in an experimental state. diff --git a/beps/0001-notifications-system/UserNotificationSettings.png b/beps/0001-notifications-system/UserNotificationSettings.png new file mode 100644 index 0000000000..de9a5881b4 Binary files /dev/null and b/beps/0001-notifications-system/UserNotificationSettings.png differ diff --git a/beps/0002-dynamic-frontend-plugins/README.md b/beps/0002-dynamic-frontend-plugins/README.md index 6581457e06..f26a3b488d 100644 --- a/beps/0002-dynamic-frontend-plugins/README.md +++ b/beps/0002-dynamic-frontend-plugins/README.md @@ -67,7 +67,7 @@ The overarching goal of this proposal is to outline the full path of how fronten - **Distribution**: How these artifacts are deployed or published and made available for apps to load. - **Loading**: How an app is able to load these artifacts from remote or local sources at runtime. -Each of these may have multiple possible solutions, in particular the loading and distribution steps. This proposal should aim to provide the minimum solutions that avoids the need for each adopter to have to re-bundle open source plugins, while still making it simple to use dynamic installation for their own internal plugins. +Each of these may have multiple possible solutions, in particular the loading and distribution steps. This proposal should aim to provide a solution that makes it possible to re-bundle 3rd party plugins to make it possible to install them dynamically, as well as a simple solution to deploy internal plugins for dynamic installation into an app. There are a couple of sub-goals that are important for this to work: @@ -84,6 +84,8 @@ and make progress. The **integration** of installed plugins and features is not in scope for this proposal, that is the responsibility of the new frontend system. +This proposal does not aim to provide a solution for re-building packages on the fly. Plugins must be pre-built for it to be possible to dynamically install them into an app. This means that a solution where you can directly install existing packages from NPM is not in scope. + This proposal does not contain any form of visual interface for managing dynamically installed plugins. The scope of this proposal only includes configuration of dynamic plugins through static configuration and TypeScript interfaces. This proposal does not aim to make it possible to add or remove plugins into an already running frontend app instance as created by `createApp` from the Backstage core APIs. The page must be reloaded for any updates to take effect. @@ -217,6 +219,12 @@ This can be checked by debugging network traffic and shared scopes: ![notifications system architecture diagram](./scope-sharing.png) +#### Limitations + +A limitation of module sharing is that each module name can only appear once in each context. This means that if you're trying to build a bundle of shared modules with a deeper dependency tree, you may end up needing to resolve conflicts by renaming some modules that appear multiple times with different versions. This will in turn limit sharing of those modules with other bundles. + +There is also a conflict with the chunk splitting currently used in the Backstage CLI that means that some singleton modules need to be configured to be eagerly loaded. More broadly we may also want to re-evaluate the chunk splitting strategy in the Backstage CLI when adding support for module federation. + ### Plugin manifest Each plugin should have a manifest file with important metadata. This metadata is used to load the remote assets to browser. The plugin manifest should be part of a build output. @@ -496,6 +504,8 @@ Theoretically plugins can be hosted on some "public CDN" which is detached from Assets can be also be hosted in the same way as they have always been. +It's important to consider old deployments as part of this storage, to make sure that dynamic chunks are still available to users who have not yet refreshed the page to load the latest version of the app. + ### Plugin discovery How to notify/send data to browser @@ -555,8 +565,16 @@ List any dependencies that this work has on other BEPs or features. ## Alternatives - +### Runtime packaging of NPM packages + +A solution that has been considered is to allow for the installation of NPM packages directly into the app, with them being repackaged for dynamic installation on the fly. This allows for a more direct way of installing plugins, without the need to change how plugins are published to NPM. The downside of this approach is that it leaves validation and dependency management to the runtime and operator of the Backstage instance. + +The NPM ecosystem is built around using version ranges along with lockfiles for dependency management. It is generally up to the maintainers of a repo to make sure that the specific dependency versions installed are all compatible with each other and do not introduce security vulnerabilities. This can be a fairly complex problem, and pushing it to the runtime installation of each plugin ends up being a significant risk. + +We consider it to be a better approach to push this responsibility down one step from Backstage operators, either to plugin maintainers, or to a service that is able to bundle and validate plugin bundles before they are installed into a Backstage instance. Building and running such as service as part of the Backstage open source project is out of scope for this proposal, but is something that could be considered in the future. + +### Publish dynamic bundle to NPM + +We could modify the plugin build process to also output a module federation bundle for dynamic installation. This would also allow for direct installation of plugins directly from NPM, but puts a responsibility on each plugin maintainer to keep publishing new versions of the plugin to NPM simply to update transitive dependencies. This significantly increases the effort of maintaining a Backstage plugin. + +The dynamic installation bundle can also be quite large, depending on the dependency tree of each plugin. There is a risk that the size of `node_modules` in a Backstage increases significantly, potentially hurting the development experience by increasing installation time both locally and in CI. diff --git a/beps/0008-docs-personas-framework-portal/README.md b/beps/0008-docs-personas-framework-portal/README.md new file mode 100644 index 0000000000..07468b7c4a --- /dev/null +++ b/beps/0008-docs-personas-framework-portal/README.md @@ -0,0 +1,347 @@ +--- +title: Improved Backstage Documentation with Personas +status: provisional +authors: + - '@waldirmontoya25' + - '@aramissennyeyd' +owners: +project-areas: + - core +creation-date: 2024-03-18 +--- + +# BEP: Enhancing Backstage Documentation: Personas, Framework, and Developer Portal + +[**Discussion Issue**](https://github.com/backstage/backstage/issues/23689) + +- [BEP: Enhancing Backstage Documentation: Personas, Framework, and Developer Portal](#bep-enhancing-backstage-documentation-personas-framework-and-developer-portal) + - [Summary](#summary) + - [Motivation](#motivation) + - [Goals](#goals) + - [Non-Goals](#non-goals) + - [Proposal](#proposal) + - [Design Details](#design-details) + - [Personas](#personas) + - [User](#user) + - [Documentation Style](#documentation-style) + - [Administrator](#administrator) + - [Documentation Style](#documentation-style-1) + - [Integrator](#integrator) + - [Documentation Style](#documentation-style-2) + - [Contributor](#contributor) + - [Documentation Style](#documentation-style-3) + - [Business Stakeholder](#business-stakeholder) + - [Documentation Style](#documentation-style-4) + - [Release Plan](#release-plan) + - [Dependencies](#dependencies) + - [Example Table of Contents](#example-table-of-contents) + +## Summary + +This BEP proposes restructuring the Backstage documentation to emphasize the dual nature of Backstage as both a framework for building developer portals and a fully functional developer portal out of the box, as demonstrated by the demo site. The documentation will be divided into two main sections: One focusing on the developer portal that users get with the core plugins, and another on the framework that allows integrators and builders to create their own developer portal. The goal is to improve clarity, navigation, and adoption of Backstage by positioning it as both a ready-to-use developer portal and a framework for building custom developer portals. + +## Motivation + +The current Backstage documentation has been reported to be difficult to navigate, making it challenging for different personas across the DevEx ecosystem to extract value. The CNCF [**assessment**](https://github.com/cncf/techdocs/tree/main/assessments/0008-backstage/) and the resulting [**issues**](https://github.com/backstage/backstage/issues/21893) highlight the need for improvement in the documentation structure. + +### Goals + +- Divide the documentation into two section: Framework and Developer Portal +- Define the personas Backstage is targeting +- Structure the documentation to cater the different personas +- Move the existing content to the appropriate section + +### Non-Goals + +- Rewrite the entire documentation from scratch +- Write additional content beyond the scope of the existing documentation + +## Proposal + +The proposed restructuring of the Backstage documentation revolves around two core ideas: + +1. Positioning Backstage as both a framework to build developer portals and a developer portal itself, and splitting the documentation into two main sections: + + - Developer Portal: Focusing on the features, configuration, and usage of the developer portal that users get out of the box with the core plugins. + - Framework: Covering the aspects of Backstage as a framework, including guides for integrators and builders who want to create their own developer portal using Backstage. + +2. Defining the personas participating in Backstage adoption journeys to improve documentation navigation. The identified personas are: + + - **End User**: A person who uses Backstage to find information, use plugins, and consume the developer portal. + - **Administrator/Operator**: A person who configures, secures, and deploys the developer portal, manages plugins, and oversees the general administration of the developer portal. + - **Integrator/Builder**: A person who builds plugins, customizes the code and design, and creates custom-built developer portals based on the Backstage framework. This includes developers and designers and anyone adding new functionality to their own Backstage instance. + - **Product Manager/Business stakeholders**: A person who defines the strategy for adopting Backstage, identifies use cases, communicates the value proposition for adopting Backstage and connects the developer portal to the business strategy. + - **Contributor**: A person who contributes to the Backstage upstream ecosystem. + +The adoption strategy would be as follows: + +- Create a dedicated page describing the personas Backstage is targeting and the documentation sections that cater to each persona. +- Restructure the documentation into the two new sections (Framework and Developer Portal) and redistribute the existing content accordingly. +- Publish a blog post announcing the changes, highlighting Backstage's positioning as both a framework and a developer portal, and explaining the benefits of the restructured documentation. + +The benefits of restructuring the documentation according to these ideas include: + +1. Easier navigation and discoverability of information for different personas and use cases. +2. Clear separation of runtime and development documentation. +3. Simplified process for contributors to determine the appropriate location for new documentation. +4. Streamlined Backstage adoption process for new adopters. + +## Design Details + +- The Docs section of the microsite will be divided into two top-level sections: Framework and Developer Portal. +- The structure of the Table of Contents will align with the outline proposed in https://github.com/backstage/backstage/issues/21946. + +### Personas + +#### User + +Users navigate the developer portal to access tools, information, and plugins essential for their daily tasks. They rely on Backstage to effortlessly find resources, utilize integrations, and connect with other tools and services within their ecosystem. Their interaction is predominantly with the frontend of the portal, where ease of use, accessibility, and relevant content discovery are critical. + +##### Documentation Style + +Documentation for this persona should be about usability of the portal once it is running. For example: + +- Understanding the mechanics of the Software Catalog +- Registering components +- Deleting components +- How the source of truth is the external tool linked through the plugins +- Understand dependencies relations and the overall schema of the catalog +- Using available scaffolder actions +- Customizing new workflows with available actions +- Searching +- Using available plugins +- Step by step tutorials + +#### Administrator + +Administrators are responsible for the behind-the-scenes technical setup and maintenance of the Backstage portal. This includes deploying the portal, configuring plugins, managing user access, and ensuring the security and performance of the system. They interact with both the frontend and backend, often using command-line tools, administrative dashboards, and configuration files to perform their tasks. + +##### Documentation Style + +Documentation written for this persona should be DevOps technical, assuming a strong DevOps background. The goal with administrator documentation is to give administrators a strong understanding of how to deploy and manage a Backstage Developer Portal, best practices. For example: + +- Installing and upgrading +- Configuring + - Authentication + - Plugins +- Ingesting data (users/groups/components, etc) +- Installing plugins +- Implement Git Flows for the Developer portal +- Creating Pipelines for Docs generation +- Troubleshooting + +#### Integrator + +Integrators actively work on extending and customizing Backstage. This includes developing new plugins, customizing the UI/UX, and integrating external services or data sources. Their work is deeply technical, involving coding, and engaging with the Backstage community for support and collaboration. They need a deep understanding of the Backstage architecture and APIs, working closely with both the framework's backend and frontend aspects. + +##### Documentation Style + +Documentation written for this persona should be software technical, assuming a strong software background. While we can assume an overall technical knowledge, where possible we should link out to useful guides for the technologies we use, ex: Node.js, express.js, React, etc. The goal with documentation written for integrators is to give them a strong understanding of how to use the Backstage framework to build/evolve a company's Backstage Developer Portal, orient them to get support from the open source community, and prepare them for continuing to deliver value for their Backstage Developer Portal. For example: + +- API references +- Frontend and Backend systems +- Package architecture +- Extending the Software Catalog +- Creating custom themes +- Integrating new react components +- Building custom authentication providers/strategies +- Accessibility + +#### Contributor + +Contributors are involved in the development of the Backstage framework itself. They contribute to the core codebase, develop new features, fix bugs, create documentation and maintain the overall health of the project. They are deeply involved in the open-source community, collaborating with maintainers and other contributors to improve the framework and its ecosystem. + +##### Documentation Style + +The goal with documentation written for contributors is to give them a strong understanding of how to contribute to the Backstage framework, orient them to get support from the open source community, and prepare them for continuing to deliver value for the Backstage framework. For example: + +- Contributing to the Backstage framework +- Setting up a development environment +- Writing tests +- Writing documentation + +#### Business Stakeholder + +Business stakeholders use Backstage to align technical capabilities with business goals, monitoring how features and plugins support operational efficiency, developer satisfaction, and strategic objectives. They are involved in defining the strategy and measuring the impact of the developer portal on the organization. They need to navigate through dashboards, reports, and analytics within Backstage to gather insights and make informed decisions. + +##### Documentation Style + +Documentation written for this persona should be strategic, assuming a strong background in business development and strategy. The goal for business documentation is to give a strong understanding of what Backstage Developer Portal can do for their company, how to deliver value quickly and continuously and guides for pitching or driving Backstage adoption. For example: + +- Adoption use cases +- Adoption strategies +- Measuring success +- Case studies + +## Release Plan + +- Release the BEP by 03/24/2024. +- Discuss the changes with the community and gather feedback by 04/24/2024. +- Implement the changes by 04/30/2024. + +## Dependencies + +None + +## Example Table of Contents + +- Overview + - "The overview should introduce users to the concept of Backstage, what an IDP is, how to deliver value, why you should care about DevEx, etc." + - What is Backstage? + - Roadmap + - Vision + - Release and Versioning Policy + - Backstage Threat Model + - Logo assets + - Support and community +- Framework + - Architecture Overview + - "The arch overview should explain how the framework is structured, where plugins and instances fit in and how to understand the current design of Backstage." + - Getting Started + - Integrator/Builder Guides + - Local Development + - "Prepare users for how to develop locally, debug problems, run tests, etc." + - CLI + - Linking in local packages + - Debugging Backstage + - Backstage core framework + - "Internal documentation." + - Systems + - Frontend + - Old + - New + - Backend + - Old + - New + - API Reference + - "Internal documentation" + - Building plugins + - "How to build a plugin, how to integrate it with other plugins, how to deploy and monitor it, and how to iterate on plugin development." + - Intro to plugins + - Existing plugins + - Creating a new plugin + - Plugin development + - Structuring a plugin + - Integrating with other systems + - Integrating with the Catalog + - Integrating Search + - Composability system + - Internationalization + - Plugin analytics + - Feature flags + - OpenAPI + - Backends and APIs + - Testing + - Publishing + - Core Plugins + - "How to leverage the existing plugins for your new plugin or customization options." + - Home Page + - Customizing the home page + - Software Catalog + - Extending the model + - External integrations + - Catalog Customization + - API + - Software Templates + - Writing custom actions + - Writing tests for actions + - Writing custom field extensions + - Writing custom step layouts + - Authorizing parameters, steps and actions + - Migrating to react-jsonschema-form@v5 + - Migrating to v1beta3 templates + - Search + - Overview + - Getting Started with search + - Search concepts + - Search architecture + - Search Engines + - How to Guides + - TechDocs + - Customizing TechDocs + - TechDocs add-ons + - Kubernetes + - Customizing the kubernetes plugin + - Authentication + - Proxy + - Permissions + - Overview + - Concepts + - Getting Started + - Writing a permission policy + - Frontend integration + - Defining custom permission rules + - Using permissions in plugins + - Designing for Backstage + - ADRs + - Accessibility + - References + - Contributor Guides + - "How to get started contributing to OSS." + - Contributing to Backstage + - Reference +- Developer Portal + - Architecture Overview + - Getting Started + - Administrator Guides + - Developer Portal + - "How do I deploy, monitor, configure and verify my Backstage Developer Portal?" + - Installing and Configuring + - Database + - Authentication + - Installing plugins + - Customize the design + - Securing + - Deploying in Production + - Integrating with other systems + - Managing + - Monitoring + - Troubleshooting + - Upgrading + - Keeping backstage up to date + - Customizing + - Core Plugins + - "How do I install and configure Backstage Developer Portal with plugins." + - Home Page + - Installing and Configuring + - Software Catalog + - Overview + - The life of an Entity + - Catalog Configuration + - System Model + - YAML file format + - Entity Reference + - Well Known annotations + - Well known relations + - Well known statuses + - Creating the catalog graph + - Software Templates + - Overview + - Configuring + - Adding a new template + - Writing a template + - Built in actions + - TechDocs + - Overview + - Getting Started + - Architecture + - Installing and configuring + - Using Cloud Storage for TechDocs generated files + - Configuring CI/CD to generate and publish TechDocs sites + - TechDocs CLI + - Troubleshooting + - Kubernetes + - Installing and Configuring + - Authentication + - Troubleshooting + - Search + - Product Manager Guides + - "How do I present Backstage to leadership, what are the benefits, why should I care, etc." + - Strategies for adopting + - Use cases + - User Guides + - "How do I use the default OSS Backstage" + - Logging in + - Registering a component + - Creating a new component + - Reference diff --git a/contrib/docker/minimal-harded-image/README.md b/contrib/docker/minimal-harded-image/README.md deleted file mode 100644 index accb2188ac..0000000000 --- a/contrib/docker/minimal-harded-image/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Minimal Hardened Image for Backstage - -DockerHub images in general did not seem ideal for Backstage as the number of vulnerabilities were quite high regardless of the image used. - -The `Dockerfile` in this directory uses a [`wolfi-base`](https://github.com/wolfi-dev) image from Chainguard Images. This improves the security of the application and reduces false positives in scanners. - -## Considerations - -- `Wolfi` only releases the `latest` tag for public consumption however digests can be pinned. -- `Wolfi` OS uses packages from the [os repository](https://github.com/wolfi-dev/os) on GitHub. Some packages may be named differently. -- While `Wolfi` uses `apk`, the OS is designed to support `glibc`. -- Due to the stripped down nature of the base image, additional packages might be needed compared to a distribution like Debian or Ubuntu. diff --git a/contrib/docker/minimal-harded-image/Dockerfile b/contrib/docker/minimal-hardened-image/Dockerfile similarity index 100% rename from contrib/docker/minimal-harded-image/Dockerfile rename to contrib/docker/minimal-hardened-image/Dockerfile diff --git a/contrib/docker/minimal-hardened-image/README.md b/contrib/docker/minimal-hardened-image/README.md new file mode 100644 index 0000000000..62045a4ded --- /dev/null +++ b/contrib/docker/minimal-hardened-image/README.md @@ -0,0 +1,25 @@ +# Minimal Hardened Image for Backstage + +DockerHub images in general did not seem ideal for Backstage as the number of vulnerabilities were quite high regardless of the image used. + +The `Dockerfile` in this directory uses a [wolfi-base](https://github.com/wolfi-dev) image from Chainguard Images. This improves the security of the application and reduces false positives in scanners. + +## Pinning Digest + +To reduce maintenance, the digest of the image has been removed from the `./Dockerfile` file. A complete example with the digest would be `cgr.dev/chainguard/wolfi-base:latest@sha256:3d6dece13cdb5546cd03b20e14f9af354bc1a56ab5a7b47dca3e6c1557211fcf` and it is suggested to update the `FROM` line in the `Dockerfile` to use a digest. + +Using the digest allows tools such as Dependabot or Renovate to know exactly which image digest is being utilized and allows for Pull Requests to be triggered when a new digest is available. It is suggested to setup Dependabot/Renovate or a similar tool to ensure the image is kept up to date so that vulnerability fixes that have been addressed are pulled in frequently. + +### Obtaining Digest + +To obtain the latest digest, perform a `docker pull` on the image to get the latest digest in the command output or use `crane digest `. + +## Considerations + +- Wolfi only releases the `latest` tag for public consumption however digests can be pinned. +- Wolfi OS uses packages from the [os repository](https://github.com/wolfi-dev/os) on GitHub. + - Some packages may be named differently. +- While Wolfi uses `apk`, the OS is designed to support `glibc`. +- Due to the stripped down nature of the base image, additional packages might be needed compared to a distribution like Debian or Ubuntu. +- Chainguard will maintain one version of each Wolfi package at a time, which will track the latest version of the upstream software in the package. Chainguard will end patch support for previous versions of packages in Wolfi. [Read more here](https://edu.chainguard.dev/chainguard/chainguard-images/faq/#what-packages-are-available-in-chainguard-images) + - It is encouraged to use a relative pin or use a third-party tool to ensure the packages are kept up to date diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index 838aaffef6..8c858bea0f 100644 --- a/contrib/docs/tutorials/authenticate-api-requests.md +++ b/contrib/docs/tutorials/authenticate-api-requests.md @@ -3,8 +3,7 @@ > [!CAUTION] > This entire guide MUST NOT BE USED by users of Backstage 1.26 and > newer. If you have applied the changes in this guide, you need to remove them -> again as you upgrade to recent versions of Backstage. When [the new auth -> changes](https://github.com/backstage/backstage/tree/master/beps/0003-auth-architecture-evolution) +> again as you upgrade to recent versions of Backstage. When [the new auth changes](https://github.com/backstage/backstage/tree/master/beps/0003-auth-architecture-evolution) > landed backends became natively secured through the framework, and the > instructions outlined in here can interfere with the backend functioning > correctly. diff --git a/contrib/docs/tutorials/aws-deployment.md b/contrib/docs/tutorials/aws-deployment.md index 6edbb73f9d..d43d8aefb0 100644 --- a/contrib/docs/tutorials/aws-deployment.md +++ b/contrib/docs/tutorials/aws-deployment.md @@ -1,11 +1,9 @@ # Deploying Backstage on AWS using ECR and EKS -Backstage documentation shows how to build a [Docker -image](https://backstage.io/docs/deployment/docker); this +Backstage documentation shows how to build a [Docker image](https://backstage.io/docs/deployment/docker); this tutorial shows how to deploy that Docker image to AWS using Elastic Container Registry (ECR) and Elastic Kubernetes Service (EKS). Amazon also supports -deployments with Helm, covered in the [Helm -Kubernetes](../../kubernetes/basic_kubernetes_example_with_helm) example. +deployments with Helm, covered in the [Helm Kubernetes](../../kubernetes/basic_kubernetes_example_with_helm) example. The basic workflow for this method is to build a Backstage Docker image, upload the new version to a container registry, and update a Kubernetes deployment with @@ -13,8 +11,7 @@ the new image. ## Create a container registry -To create an Elastic Container Registry on AWS, go to the [AWS ECR -console](https://console.aws.amazon.com/ecr/repositories). +To create an Elastic Container Registry on AWS, go to the [AWS ECR console](https://console.aws.amazon.com/ecr/repositories). Click `Create repository` and give the repository a name, like `backstage`. @@ -35,8 +32,7 @@ Go to [AWS IAM console](https://console.aws.amazon.com/iam/home) and select ## Publish a Backstage build -Follow the [Docker -image](https://backstage.io/docs/deployment/docker) +Follow the [Docker image](https://backstage.io/docs/deployment/docker) documentation to build a new Backstage Docker image: ```shell @@ -56,8 +52,7 @@ Default region name: Now you can use the AWS CLI to push the built image to the ECR repository. It's a good practice to use a specific version tag as well as `latest` when pushing; -more about [Semver tagging -here](https://medium.com/@mccode/using-semantic-versioning-for-docker-image-tags-dfde8be06699). +more about [Semver tagging here](https://medium.com/@mccode/using-semantic-versioning-for-docker-image-tags-dfde8be06699). Go to the [AWS ECR console](https://console.aws.amazon.com/ecr/repositories) and click on your repository, then `View push commands`. This will show the @@ -83,12 +78,10 @@ Kubernetes deployment based on this image. Creating an Elastic Kubernetes Service (EKS) cluster is beyond the scope of this document, but it can be as easy as `eksctl create cluster` documented in the -[AWS EKS getting started -guide](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html), +[AWS EKS getting started guide](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html), which uses a Cloudformation template to create the necessary resources. -To deploy the Docker image to EKS, follow the [Kubernetes -guide](https://backstage.io/docs/deployment/k8s#creating-the-backstage-instance) +To deploy the Docker image to EKS, follow the [Kubernetes guide](https://backstage.io/docs/deployment/k8s#creating-the-backstage-instance) but set the Backstage deployment `image` to the ECR repository URL: ```yaml @@ -110,8 +103,7 @@ spec: ... ``` -Create the [Service -descriptor](https://backstage.io/docs/deployment/k8s#creating-a-backstage-service) +Create the [Service descriptor](https://backstage.io/docs/deployment/k8s#creating-a-backstage-service) as well, and apply these Kubernetes definitions to the EKS cluster to complete the Backstage deployment: @@ -120,16 +112,14 @@ $ kubectl apply -f kubernetes/backstage.yaml $ kubectl apply -f kubernetes/backstage-service.yaml ``` -Now you can see your Backstage workload running from the [EKS -console](https://console.aws.amazon.com/eks/home). +Now you can see your Backstage workload running from the [EKS console](https://console.aws.amazon.com/eks/home). ## Further steps ### Exposing Backstage with a load balancer To make the service useful, we need to expose the workload with a load balancer. -Follow the [Application load balancing on -EKS](https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html) guide to +Follow the [Application load balancing on EKS](https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html) guide to set up a Load Balancer controller and Kubernetes ingress to your application. This is ultimately a `kubectl apply` with an ingress definition: diff --git a/docs/accessibility/index.md b/docs/accessibility/index.md index b4d63fd4e4..da10d60dd2 100644 --- a/docs/accessibility/index.md +++ b/docs/accessibility/index.md @@ -47,7 +47,10 @@ If you want to use the Lighthouse CLI and run the checks based on the config you yarn dlx @lhci/cli@0.11.x autorun ``` -> Note: running this command will use the [Lighthouse config](https://github.com/backstage/backstage/blob/39ba2284d73885b7ca8290cb38e2b1e4d983c8d6/lighthouserc.js#L19-L34) so make sure to adjust it to your needs if needed. +:::note Note +Running this command will use the [Lighthouse config](https://github.com/backstage/backstage/blob/39ba2284d73885b7ca8290cb38e2b1e4d983c8d6/lighthouserc.js#L19-L34) so make sure to adjust it to your needs if needed. + +::: ### Use Lighthouse Github Action on your own repo diff --git a/docs/assets/architecture-overview/package-architecture.drawio.svg b/docs/assets/architecture-overview/package-architecture.drawio.svg index df8c0f8820..89fab2647d 100644 --- a/docs/assets/architecture-overview/package-architecture.drawio.svg +++ b/docs/assets/architecture-overview/package-architecture.drawio.svg @@ -1,69 +1,66 @@ - + - - - - - - - - - - + + + + + + + + + - +
-
-
+
+
app
- + app - - - - - - + + + + - +
-
-
+
+
backend
- + backend - - - - - - + + + + + + - +
-
-
+
+
plugin-<plugin-id>
@@ -74,19 +71,19 @@ - - - - - - + + + + + + - +
-
-
+
+
plugin-<plugin-id>-backend
@@ -97,69 +94,9 @@ - - - - - - Backend Libraries - - - - - - -
-
-
- @backstage/backend-common -
-
-
-
- - @backstage/backend-common - -
-
- - - - -
-
-
- @backstage/backend-test-utils -
-
-
-
- - @backstage/backend-test-utils - -
-
- - - - -
-
-
- @backstage/backend-tasks -
-
-
-
- - @backstage/backend-tasks - -
-
- - - - + + + Common Libraries @@ -167,16 +104,16 @@ - +
-
-
+
+
@backstage/catalog-client
- + @backstage/catalog-client @@ -184,16 +121,16 @@ - +
-
-
+
+
@backstage/types
- + @backstage/types @@ -201,16 +138,16 @@ - +
-
-
+
+
@backstage/config
- + @backstage/config @@ -218,16 +155,16 @@ - +
-
-
+
+
@backstage/errors
- + @backstage/errors @@ -235,16 +172,16 @@ - +
-
-
+
+
@backstage/catalog-model
- + @backstage/catalog-model @@ -252,24 +189,23 @@ - +
-
-
+
+
@backstage/integration
- + @backstage/integration - - - - + + + Frontend App Core @@ -277,16 +213,16 @@ - +
-
-
+
+
@backstage/core-app-api
- + @backstage/core-app-api @@ -294,36 +230,36 @@ - +
-
-
+
+
@backstage/app-defaults
- + @backstage/app-defaults - - - - - - - - - + + + + + + + + + - +
-
-
+
+
plugin-<plugin-id>-backend-module-<module-id>
@@ -334,17 +270,17 @@ - - - - + + + + - +
-
-
+
+
plugin-<plugin-id>-module-<module-id>
@@ -355,10 +291,9 @@ - - - - + + + Common Tooling @@ -366,28 +301,27 @@ - +
-
-
+
+
@backstage/cli
- + @backstage/cli - - - - - - - - + + + + + + + External Plugin Libraries @@ -395,16 +329,16 @@ - +
-
-
+
+
plugin-<other-plugin-id>-react
- + plugin-<other-plugin-id>-react @@ -412,16 +346,16 @@ - +
-
-
+
+
plugin-<other-plugin-id>-common
- + plugin-<other-plugin-id>-common @@ -429,30 +363,29 @@ - +
-
-
+
+
plugin-<other-plugin-id>-node
- + plugin-<other-plugin-id>-node - - - - - - - - - - + + + + + + + + + Plugin Libraries @@ -460,10 +393,10 @@ - +
-
-
+
+
plugin-<plugin-id>-react
@@ -477,10 +410,10 @@ - +
-
-
+
+
plugin-<plugin-id>-common
@@ -494,10 +427,10 @@ - +
-
-
+
+
plugin-<plugin-id>-node
@@ -508,13 +441,11 @@ - - - - - - - + + + + + Frontend Plugin Core @@ -522,16 +453,16 @@ - +
-
-
+
+
@backstage/core-plugin-api
- + @backstage/core-plugin-api @@ -539,16 +470,16 @@ - +
-
-
+
+
@backstage/test-utils
- + @backstage/test-utils @@ -556,24 +487,23 @@ - +
-
-
+
+
@backstage/dev-utils
- + @backstage/dev-utils - - - - + + + Frontend Libraries @@ -581,16 +511,16 @@ - +
-
-
+
+
@backstage/integration-react
- + @backstage/integration-react @@ -598,16 +528,16 @@ - +
-
-
+
+
@backstage/core-components
- + @backstage/core-components @@ -615,131 +545,276 @@ - +
-
-
+
+
@backstage/theme
- + @backstage/theme - - - - + + + + - -
-
-
+ +
+
+
Frontend Package
- + Frontend Package - -
-
-
+ +
+
+
Isomorphic Package
- + Isomorphic Package - -
-
-
+ +
+
+
Backend Package
- + Backend Package - + - -
-
-
+ +
+
+
CLI Package
- + CLI Package - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - -
-
-
+ +
+
+
Compatibility
- + Compatibility - - - - + + + + + + + + Backend App Core + + + + + + +
+
+
+ @backstage/backend-app-api +
+
+
+
+ + @backstage/backend-app-api + +
+
+ + + + +
+
+
+ @backstage/backend-defaults +
+
+
+
+ + @backstage/backend-defaults + +
+
+ + + + + + + + + Backend Plugin Core + + + + + + +
+
+
+ @backstage/backend-plugin-api +
+
+
+
+ + @backstage/backend-plugin-api + +
+
+ + + + +
+
+
+ @backstage/backend-test-utils +
+
+
+
+ + @backstage/backend-test-utils + +
+
+ + + + +
+
+
+ @backstage/backend-dev-utils +
+
+
+
+ + @backstage/backend-dev-utils + +
+
+ + + + + Backend Libraries + + + + + + +
+
+
+ @backstage/backend-tasks +
+
+
+
+ + @backstage/backend-tasks + +
+
+ + + + +
+
+
+ @backstage/backend-openapi-utils +
+
+
+
+ + @backstage/backend-openapi-utils + +
+
+ + - Viewer does not support full SVG 1.1 + Text is not SVG - cannot display diff --git a/docs/assets/software-catalog/software-model-entities.drawio.svg b/docs/assets/software-catalog/software-model-entities.drawio.svg index d087583245..122f58b065 100644 --- a/docs/assets/software-catalog/software-model-entities.drawio.svg +++ b/docs/assets/software-catalog/software-model-entities.drawio.svg @@ -1,4 +1,4 @@ - + -
Domain
(e.g.  domain
models, metrics, KPIs, business purpose)
Domain...
partOf
partOf
System
Collection of entities that cooperate to perform some function
System...
dependsOn
dependsOn
partOf
partOf
Resource
(e.g. SQL Database, S3 bucket, ...)
Resource...
consumesAPI
consumesAPI
API
(e.g. OpenAPI, gRPC API, Avro, Dataset, ...)
API...
providesAPI
providesAPI
partOf
partOf
Component
(e.g. backend service, data pipeline ...)
Component...
partOf
partOf
dependsOn
dependsOn
Kind: Group
Kind: Group
Kind: User
Kind: User
OwnerOf
OwnerOf
OwnedBy
OwnedBy
Service
Service
website
website
website
website
Types
Types
service
service
website
website
library
library
asyncapi
asyncapi
graphql
graphql
grpc
grpc
Types
Types
openapi
openapi
business-unit
business-unit
product-area
product-area
root
root
Types
Types
team
team
s3-bucket
s3-bucket
cluster
cluster
Types
Types
database
database
Kind: Template
Parameters rendered in the
frontend and the steps executed in  the scaffolding process
Kind: Template...
Kind: Location
a marker that references other places to look for catalog data
Kind: Location...
memberOf
memberOf
hasMember
hasMember
parentOf
parentOf
childOf
childOf
Text is not SVG - cannot display
\ No newline at end of file +
Domain
(e.g.  domain
models, metrics, KPIs, business purpose)
partOf
System
Collection of entities that cooperate to perform some function
dependsOn
partOf
Resource
(e.g. SQL Database, S3 bucket, ...)
consumesAPI
API
(e.g. OpenAPI, gRPC API, Avro, Dataset, ...)
providesAPI
partOf
Component
(e.g. backend service, data pipeline ...)
partOf
dependsOn
Kind: Group
Kind: User
OwnerOf
OwnedBy
Service
website
website
Types
service
website
library
asyncapi
graphql
grpc
Types
openapi
business-unit
product-area
root
Types
team
s3-bucket
cluster
Types
database
Kind: Template
Parameters rendered in the
frontend and the steps executed in  the scaffolding process
Kind: Location
a marker that references other places to look for catalog data
memberOf
hasMember
parentOf
childOf
subdomainOf
\ No newline at end of file diff --git a/docs/assets/software-templates/context-menu.png b/docs/assets/software-templates/context-menu.png new file mode 100644 index 0000000000..fa4f52cc48 Binary files /dev/null and b/docs/assets/software-templates/context-menu.png differ diff --git a/docs/assets/software-templates/template-editor-dry-run.png b/docs/assets/software-templates/template-editor-dry-run.png new file mode 100644 index 0000000000..6095fb5cb0 Binary files /dev/null and b/docs/assets/software-templates/template-editor-dry-run.png differ diff --git a/docs/assets/software-templates/template-editor-load-dir.png b/docs/assets/software-templates/template-editor-load-dir.png new file mode 100644 index 0000000000..8fb22ab47c Binary files /dev/null and b/docs/assets/software-templates/template-editor-load-dir.png differ diff --git a/docs/assets/software-templates/template-start-over.png b/docs/assets/software-templates/template-start-over.png new file mode 100644 index 0000000000..67d9caff34 Binary files /dev/null and b/docs/assets/software-templates/template-start-over.png differ diff --git a/docs/assets/software-templates/template-task-list.png b/docs/assets/software-templates/template-task-list.png new file mode 100644 index 0000000000..dc2bbfa310 Binary files /dev/null and b/docs/assets/software-templates/template-task-list.png differ diff --git a/docs/auth/add-auth-provider.md b/docs/auth/add-auth-provider.md index a43e2307e6..d1dad0b183 100644 --- a/docs/auth/add-auth-provider.md +++ b/docs/auth/add-auth-provider.md @@ -4,10 +4,14 @@ title: Contributing New Providers description: Documentation on adding new authentication providers --- -> NOTE: The primary audience for this documentation are contributors to the main -> Backstage project that want to add support for new authentication providers. -> While you can follow it to implement your own custom providers it is much -> more advanced than using our built-in providers. +:::note Note + +The primary audience for this documentation are contributors to the main +Backstage project that want to add support for new authentication providers. +While you can follow it to implement your own custom providers it is much +more advanced than using our built-in providers. + +::: ## How Does Authentication Work? diff --git a/docs/auth/atlassian/provider.md b/docs/auth/atlassian/provider.md index 2680370d93..c8db009805 100644 --- a/docs/auth/atlassian/provider.md +++ b/docs/auth/atlassian/provider.md @@ -47,6 +47,12 @@ auth: clientId: ${AUTH_ATLASSIAN_CLIENT_ID} clientSecret: ${AUTH_ATLASSIAN_CLIENT_SECRET} scope: ${AUTH_ATLASSIAN_SCOPES} + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: usernameMatchingUserEntityName ``` The Atlassian provider is a structure with three configuration keys: @@ -57,6 +63,22 @@ The Atlassian provider is a structure with three configuration keys: **NOTE:** the scopes `offline_access`, `read:jira-work`, and `read:jira-user` are provided by default. +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `usernameMatchingUserEntityName`: Matches the username from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `atlassianAuthApi` reference and diff --git a/docs/auth/cloudflare/access.md b/docs/auth/cloudflare/access.md index 9df816c39f..52d9fdfc21 100644 --- a/docs/auth/cloudflare/access.md +++ b/docs/auth/cloudflare/access.md @@ -170,6 +170,5 @@ backend.add(customAuth); The body of the sign-in resolver is up to you to write! The example code above is just a copy of what `emailMatchingUserEntityProfileEmail` does. The `info` parameter contains all of the results of the sign-in attempt so far. The `ctx` -context [has several useful -functions](https://backstage.io/docs/reference/plugin-auth-node.authresolvercontext/) +context [has several useful functions](https://backstage.io/docs/reference/plugin-auth-node.authresolvercontext/) for issuing tokens in various ways. diff --git a/docs/auth/github/provider.md b/docs/auth/github/provider.md index 353b8ebe08..1604b607ff 100644 --- a/docs/auth/github/provider.md +++ b/docs/auth/github/provider.md @@ -41,9 +41,14 @@ auth: clientSecret: ${AUTH_GITHUB_CLIENT_SECRET} ## uncomment if using GitHub Enterprise # enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL} + signIn: + resolvers: + # Matches the GitHub username with the Backstage user entity name. + # See https://backstage.io/docs/auth/github/provider#resolvers for more resolvers. + - resolver: usernameMatchingUserEntityName ``` -The GitHub provider is a structure with three configuration keys: +The GitHub provider is a structure with these configuration keys: - `clientId`: The client ID that you generated on GitHub, e.g. `b59241722e3c3b4816e2` @@ -54,6 +59,25 @@ The GitHub provider is a structure with three configuration keys: initiating an OAuth flow, e.g. `https://your-intermediate-service.com/handler`. Only needed if Backstage is not the immediate receiver (e.g. one OAuth app for many backstage instances). +- `signIn`: The configuration for the sign-in process, including the **resolvers** + that should be used to match the user from the auth provider with the user + entity in the Backstage catalog (typically a single resolver is sufficient). + +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `usernameMatchingUserEntityName`: Matches the username from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. + +:::note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. ## Adding the provider to the Backstage frontend diff --git a/docs/auth/gitlab/provider.md b/docs/auth/gitlab/provider.md index ed7fa6aec3..f5613582fd 100644 --- a/docs/auth/gitlab/provider.md +++ b/docs/auth/gitlab/provider.md @@ -43,6 +43,12 @@ auth: # audience: https://gitlab.company.com ## uncomment if using a custom redirect URI # callbackUrl: https://${BASE_URL}/api/auth/gitlab/handler/frame + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: usernameMatchingUserEntityName ``` The GitLab provider is a structure with three configuration keys: @@ -56,6 +62,22 @@ The GitLab provider is a structure with three configuration keys: `https://$backstage.acme.corp/api/auth/gitlab/handler/frame` Note: Due to a peculiarity with GitLab OAuth, ensure there is no trailing `/` after 'frame' in the URL. +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `usernameMatchingUserEntityName`: Matches the username from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `gitlabAuthApi` reference and diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 410008b22e..7e6178154c 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -27,6 +27,12 @@ auth: gcp-iap: audience: '/projects//global/backendServices/' jwtHeader: x-custom-header # Optional: Only if you are using a custom header for the IAP JWT + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: emailMatchingUserEntityAnnotation ``` The full `audience` value can be obtained by visiting your [Identity-Aware Proxy Google Cloud console](https://console.cloud.google.com/security/iap), selecting your project, finding your Backend Service to proxy, clicking the 3 vertical dots then "Get JWT Audience Code", and copying from the resulting popup, which will look similar to the following: @@ -36,11 +42,48 @@ The full `audience` value can be obtained by visiting your [Identity-Aware Proxy This config section must be in place for the provider to load at all. Now let's add the provider itself. +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `emailMatchingUserEntityAnnotation`: Matches the email address from the auth provider with the User entity where the value of the `google.com/email` annotation matches. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + ## Backend Changes -This provider is not enabled by default in the auth backend code, because -besides the config section above, it also needs to be given one or more -callbacks in actual code as well as described below. +There is a module for this provider that you will need to add to your backend. + +First you'll want to run this command to add the module: + +```sh + yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-gcp-iap-provider +``` + +Then you will need to add this to your backend: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); + +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider')); +/* highlight-add-end */ +``` + +### Legacy Backend Changes + +If you are still using the legacy backend you will need to make the changes outlined here. + +This provider is not enabled by default in the auth backend code, because besides the config section above, it also needs to be given one or more callbacks in actual code as well as described below. Add a `providerFactories` entry to the router in `packages/backend/src/plugins/auth.ts`. diff --git a/docs/auth/google/provider.md b/docs/auth/google/provider.md index d3cd8f2dd2..f7802d43f7 100644 --- a/docs/auth/google/provider.md +++ b/docs/auth/google/provider.md @@ -42,6 +42,12 @@ auth: development: clientId: ${AUTH_GOOGLE_CLIENT_ID} clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET} + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: emailMatchingUserEntityAnnotation ``` The Google provider is a structure with two configuration keys: @@ -50,6 +56,22 @@ The Google provider is a structure with two configuration keys: `10023341500512-beui241gjwwkrdkr2eh7dprewj2pp1q.apps.googleusercontent.com` - `clientSecret`: The client secret tied to the generated client ID. +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `emailMatchingUserEntityAnnotation`: Matches the email address from the auth provider with the User entity where the value of the `google.com/email` annotation matches. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `googleAuthApi` reference and diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 406f789630..4140276df8 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -5,8 +5,7 @@ description: An introduction to Backstage user identities and sign-in resolvers --- :::info -This documentation is written for [the new backend -system](../backend-system/index.md) which is the default since Backstage +This documentation is written for [the new backend system](../backend-system/index.md) which is the default since Backstage [version 1.24](../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./identity-resolver--old.md) instead, and [consider migrating](../backend-system/building-backends/08-migrating.md)! @@ -31,15 +30,13 @@ testing purposes and quickly getting started locally, but is not safe for use in production and that particular provider will refuse to work there. Because of this, one of the early things you want to do when standing up your -Backstage instance is to choose a production ready auth provider. See [the auth -overview page](./index.md) for a full list of providers and how to install and +Backstage instance is to choose a production ready auth provider. See [the auth overview page](./index.md) for a full list of providers and how to install and configure them. ## Backstage User Identity A user identity within Backstage is built up from two main pieces of -information: a user [entity -reference](../features/software-catalog/references.md), and a set of ownership +information: a user [entity reference](../features/software-catalog/references.md), and a set of ownership references. When a user signs in, a Backstage token is generated which is then used to identify the user within the Backstage ecosystem. @@ -194,8 +191,7 @@ backend.add(import('@backstage/plugin-auth-backend-module-github-provider')); backend.add(customAuth); ``` -Check out [the naming patterns -article](../backend-system/architecture/07-naming-patterns.md) for what rules +Check out [the naming patterns article](../backend-system/architecture/07-naming-patterns.md) for what rules apply regarding how to form valid IDs. In this example we also put the module declaration directly in `packages/backend/src/index.ts` but that's just for simplicity. You can place it anywhere you like, including in other packages, and @@ -244,8 +240,7 @@ async signInResolver(info, ctx) { If you throw an error in the sign in resolver function, the sign in attempt is immediately rejected, and the error details are presented in the user interface. -The `ctx` context [has several useful -functions](https://backstage.io/docs/reference/plugin-auth-node.authresolvercontext/) +The `ctx` context [has several useful functions](https://backstage.io/docs/reference/plugin-auth-node.authresolvercontext/) for issuing tokens in various ways. ### Custom Ownership Resolution diff --git a/docs/auth/index.md b/docs/auth/index.md index f6282264e4..f925e52917 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -10,12 +10,16 @@ configure Backstage to have any number of authentication providers, but only one of these will typically be used for sign-in, with the rest being used to provide access to external resources. -> NOTE: Identity management and the Sign-In page in Backstage is NOT a method for blocking -> access for unauthorized users. The identity system only serves to provide a personalized -> experience and access to a Backstage Identity Token, which can be passed to backend plugins. -> This also means that your Backstage backend APIs are by default unauthenticated. -> Thus, if your Backstage instance is exposed to the Internet, anyone can access -> information in the Backstage. You can learn more [here](../overview/threat-model.md#integrator-responsibilities). +:::note Note + +Identity management and the Sign-In page in Backstage is NOT a method for blocking +access for unauthorized users. The identity system only serves to provide a personalized +experience and access to a Backstage Identity Token, which can be passed to backend plugins. +This also means that your Backstage backend APIs are by default unauthenticated. +Thus, if your Backstage instance is exposed to the Internet, anyone can access +information in the Backstage. You can learn more [here](../overview/threat-model.md#integrator-responsibilities). + +::: ## Built-in Authentication Providers @@ -141,8 +145,12 @@ const app = createApp({ }); ``` -> NOTE: You can configure sign-in to use a redirect flow with no pop-up by adding -> `enableExperimentalRedirectFlow: true` to the root of your `app-config.yaml` +:::note Note + +You can configure sign-in to use a redirect flow with no pop-up by adding +`enableExperimentalRedirectFlow: true` to the root of your `app-config.yaml` + +::: ## Sign-In with Proxy Providers diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index bb8a7db6e4..b96f175183 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -57,6 +57,12 @@ auth: domainHint: ${AZURE_TENANT_ID} additionalScopes: - Mail.Send + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: emailMatchingUserEntityAnnotation ``` The Microsoft provider is a structure with three mandatory configuration keys: @@ -70,6 +76,22 @@ The Microsoft provider is a structure with three mandatory configuration keys: For more details, see [Home Realm Discovery](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/home-realm-discovery-policy) - `additionalScopes` (optional): List of scopes for the App Registration. The default and mandatory value is ['user.read']. +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `emailMatchingUserEntityAnnotation`: Matches the email address from the auth provider with the User entity where the value of the `microsoft.com/email` annotation matches. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `microsoftAuthApiRef` reference and @@ -85,6 +107,5 @@ hosts: - `login.microsoftonline.com`, to get and exchange authorization codes and access tokens - `graph.microsoft.com`, to fetch user profile information (as seen - in [this source - code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)). + in [this source code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)). If this host is unreachable, users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in. diff --git a/docs/auth/oauth2-proxy/provider.md b/docs/auth/oauth2-proxy/provider.md index ef11827039..dca074cc7d 100644 --- a/docs/auth/oauth2-proxy/provider.md +++ b/docs/auth/oauth2-proxy/provider.md @@ -22,44 +22,30 @@ The provider configuration can be added to your `app-config.yaml` under the root auth: environment: development providers: - oauth2Proxy: {} + oauth2Proxy: + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: forwardedUserMatchingUserEntityName ``` -Right now no configuration options are supported, but the empty object is needed -to enable the provider in the auth backend. +### Resolvers -To use the `oauth2Proxy` provider you must also configure it with a sign-in resolver. -For more information about the sign-in process in general, see the -[Sign-in Identities and Resolvers](../identity-resolver.md) documentation. +This provider includes several resolvers out of the box that you can use: -For the `oauth2Proxy` provider, the sign-in result is quite different than other providers. -Because it's a proxy provider that can be configured to forward information through -arbitrary headers, the auth result simply just gives you access to the HTTP headers -of the incoming request. Using these you can either extract the information directly, -or grab ID or access tokens to look up additional information and/or validate the request. +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `forwardedUserMatchingUserEntityName`: Matches the value in the `x-forwarded-user` header from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. -A simple sign-in resolver might for example look like this: +:::note Note -```ts -providerFactories: { - ...defaultAuthProviderFactories, - oauth2Proxy: providers.oauth2Proxy.create({ - signIn: { - async resolver({ result }, ctx) { - const name = result.getHeader('x-forwarded-user'); - if (!name) { - throw new Error('Request did not contain a user') - } - return ctx.signInWithCatalogUser({ - entityRef: { name }, - }); - }, - }, - }), -}, -``` +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. -[An example on how to sign a user in without a matching user](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/auth.ts) +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. ## Adding the provider to the Backstage frontend diff --git a/docs/auth/okta/provider.md b/docs/auth/okta/provider.md index 2242e4a0f0..6fe7a8b992 100644 --- a/docs/auth/okta/provider.md +++ b/docs/auth/okta/provider.md @@ -29,7 +29,7 @@ To add Okta authentication, you must create an Application from Okta: The configuration examples provided above are suitable for local development. For a production deployment, substitute `http://localhost:7007` with the url that your Backstage instance is available at. -# Configuration +## Configuration The provider configuration can then be added to your `app-config.yaml` under the root `auth` configuration: @@ -47,6 +47,12 @@ auth: idp: ${AUTH_OKTA_IDP} # Optional # https://developer.okta.com/docs/reference/api/oidc/#scope-dependent-claims-not-always-returned additionalScopes: ${AUTH_OKTA_ADDITIONAL_SCOPES} # Optional + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: emailMatchingUserEntityAnnotation ``` The values referenced are found on the Application page on your Okta site. @@ -61,6 +67,22 @@ The values referenced are found on the Application page on your Okta site. `additionalScopes` is an optional value, a string of space separated scopes, that will be combined with the default `scope` value of `openid profile email offline_access` to adjust the `scope` sent to Okta during OAuth. This will have an impact on [the dependent claims returned](https://developer.okta.com/docs/reference/api/oidc/#scope-dependent-claims-not-always-returned). For example, setting the `additionalScopes` value to `groups` will result in the claim returning a list of the groups that the user is a member of that also match the ID token group filter of the client app. +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `emailMatchingUserEntityAnnotation`: Matches the email address from the auth provider with the User entity where the value of the `okta.com/email` annotation matches. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `oktaAuthApi` reference and diff --git a/docs/auth/service-to-service-auth.md b/docs/auth/service-to-service-auth.md index c1d6643769..ee88e45305 100644 --- a/docs/auth/service-to-service-auth.md +++ b/docs/auth/service-to-service-auth.md @@ -6,8 +6,7 @@ description: This section describes service to service authentication works, bot --- :::info -This documentation is written for [the new backend -system](../backend-system/index.md) which is the default since Backstage +This documentation is written for [the new backend system](../backend-system/index.md) which is the default since Backstage [version 1.24](../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./service-to-service-auth--old.md) instead, and [consider migrating](../backend-system/building-backends/08-migrating.md)! @@ -81,6 +80,51 @@ header: Authorization: Bearer eZv5o+fW3KnR3kVabMW4ZcDNLPl8nmMW ``` +## JWKS Token Auth + +This access method allows for external caller token authentication using configured +JSON Web Key Sets (JWKS). This is useful for callers that are authenticating to our +instance of Backstage with third-party tools, such as Auth0. + +You can configure this access method by adding one or more entries of type `jwks` +to the `backend.auth.externalAccess` app-config key: + +```yaml title="in e.g. app-config.production.yaml" +backend: + auth: + externalAccess: + - type: jwks + options: + url: https://example.com/.well-known/jwks.json + issuer: https://example.com + algorithm: RS256 + audience: example, other-example + subjectPrefix: custom-prefix + - type: jwks + options: + url: https://another-example.com/.well-known/jwks.json + issuer: https://example.com +``` + +The URL should point at an unauthenticated endpoint that returns the JWKS. + +`issuer` specifies the issuer(s) of the JWT that the authenticating app will accept. +Passed JWTs must have an `iss` claim which matches one of the specified issuers. + +`algorithm` specifies the algorithm(s) that are used to verify the JWT. The passed JWTs +must have been signed using one of the listed algorithms. + +`audience` specifies the intended audience(s) of the JWT. The passed JWTs must have an "aud" +claim that matches one of the audiences specified, or have no audience specified. + +For additional details regarding the JWKS configuration, please consult your authentication +provider's documentation. + +The subject returned from the token verification will become part of the +credentials object that the request recipient plugins get. All subjects will have the prefix +`external:`, but you can also provide a custom subjectPrefix which will get appended before the +subject returned from your JWKS service (ex. `external:custom-prefix:sub`). + ## Legacy Tokens Plugins and backends that are _not_ on the new backend system use a legacy token @@ -157,8 +201,12 @@ payload: - `sub`: the exact string "backstage-server" - `exp`: one hour from the time it was generated, in epoch seconds -> NOTE: The JWT must encode the `alg` header as a protected header, such as with -> [setProtectedHeader](https://github.com/panva/jose/blob/main/docs/classes/jwt_sign.SignJWT.md#setprotectedheader). +:::note Note + +The JWT must encode the `alg` header as a protected header, such as with +[setProtectedHeader](https://github.com/panva/jose/blob/main/docs/classes/jwt_sign.SignJWT.md#setprotectedheader). + +::: The caller then passes along the JWT token with requests in the `Authorization` header: diff --git a/docs/auth/vmware-cloud/provider.md b/docs/auth/vmware-cloud/provider.md index 20115f9e75..dd7c32f700 100644 --- a/docs/auth/vmware-cloud/provider.md +++ b/docs/auth/vmware-cloud/provider.md @@ -12,14 +12,11 @@ Cloud Console and within a Backstage app required to enable this capability. ## Create an OAuth App in the VMware Cloud Console 1. Log in to the [VMware Cloud Console](https://console.cloud.vmware.com). -1. Navigate to [Identity & Access Management > OAuth - Apps](https://console.cloud.vmware.com/csp/gateway/portal/#/consumer/usermgmt/oauth-apps) - and click the [Owned - Apps](https://console.cloud.vmware.com/csp/gateway/portal/#/consumer/usermgmt/oauth-apps/owned-apps/view) +1. Navigate to [Identity & Access Management > OAuth Apps](https://console.cloud.vmware.com/csp/gateway/portal/#/consumer/usermgmt/oauth-apps) + and click the [Owned Apps](https://console.cloud.vmware.com/csp/gateway/portal/#/consumer/usermgmt/oauth-apps/owned-apps/view) tab -- if you are not an Organization Owner or Administrator but only a Member, you will not see this nav entry unless the **Developer** check box is - selected for your role (see the [Organization roles and - permissions](https://docs.vmware.com/en/VMware-Cloud-services/services/Using-VMware-Cloud-Services/GUID-C11D3AAC-267C-4F16-A0E3-3EDF286EBE53.html#organization-roles-and-permissions-0) + selected for your role (see the [Organization roles and permissions](https://docs.vmware.com/en/VMware-Cloud-services/services/Using-VMware-Cloud-Services/GUID-C11D3AAC-267C-4F16-A0E3-3EDF286EBE53.html#organization-roles-and-permissions-0) docs for details). 1. Click **Create App**, choose 'Web/Mobile app' and click **Continue**. 1. Use default settings except: @@ -43,7 +40,7 @@ Cloud Console and within a Backstage app required to enable this capability. Apps using the [new backend system](../../backend-system/index.md), can enable the VMware Cloud provider with a small modification like: -```ts title="packages/backend-next/src/index.ts" +```ts title="packages/backend/src/index.ts" import { createBackend } from '@backstage/backend-defaults'; const backend = createBackend(); @@ -107,10 +104,6 @@ export default async function createPlugin( In the above, `commonSignInResolvers.emailLocalPartMatchingUserEntityName()` can be replaced with a more suitable resolver for the app in question. -## Configure Sign-in Resolution - -See [Sign-in Identities and Resolvers](../identity-resolver.md) for details. - ## Add to Sign-in Page See the [Sign-In Configuration](../index.md#sign-in-configuration) docs for @@ -156,11 +149,16 @@ auth: development: clientId: ${APP_ID} organizationId: ${ORG_ID} + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: vmwareCloudSignInResolvers ``` -where `APP_ID` refers to the ID retrieved when creating the OAuth App, and -`ORG_ID` is the [long ID of the -Organization](https://docs.vmware.com/en/VMware-Cloud-services/services/Using-VMware-Cloud-Services/GUID-CF9E9318-B811-48CF-8499-9419997DC1F8.html#view-the-organization-id-1) +Where `APP_ID` refers to the ID retrieved when creating the OAuth App, and +`ORG_ID` is the [long ID of the Organization](https://docs.vmware.com/en/VMware-Cloud-services/services/Using-VMware-Cloud-Services/GUID-CF9E9318-B811-48CF-8499-9419997DC1F8.html#view-the-organization-id-1) in VMware Cloud for which you wish to enable sign-in. Note that VMware Cloud requires OAuth Apps to use @@ -169,3 +167,19 @@ library used by this provider requires the use of Express session middleware to do this. Therefore the value `your session secret` under `auth.session.secret` should be replaced with a long, complex and unique string which will act as a key for signing session cookies set by Backstage. + +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `vmwareCloudSignInResolvers`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will sign in the user without associating with a catalog user. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. diff --git a/docs/backend-system/architecture/03-services.md b/docs/backend-system/architecture/03-services.md index 573f6612c2..93326eb0d9 100644 --- a/docs/backend-system/architecture/03-services.md +++ b/docs/backend-system/architecture/03-services.md @@ -111,7 +111,7 @@ There are only two possible scopes for services, `'plugin'` and `'root'`. ## Root Scoped Services -If a service is defined as a root scoped service, the implementation created by the factory will be shared across all plugins and services. One other differentiating factory for root scoped services is that they are always initialized, regardless of whether any plugins depend on them or not. This makes them suitable for implementing backend-wide concerns that are not specific to any individual plugin. +If a service is defined as a root scoped service, the implementation created by the factory will be shared across all plugins and services. One other differentiating factor for root scoped services is that they are always initialized, regardless of whether any plugins depend on them or not. This makes them suitable for implementing backend-wide concerns that are not specific to any individual plugin. There is a limitation in the usage of root scoped services, which is that their implementation can only depend on other root scoped services. Plugin scoped services on the other hand can depend on both root and plugin scoped services. Because of this limitation, one of the main reasons to define a root scoped services is to make it possible for other root scoped services to depend on it. @@ -157,7 +157,7 @@ export const fooServiceFactory = createServiceFactory({ }); ``` -Whatever value is returned by the `createRootContext` function will shared and passed as the second argument to each invocation of the `factory` function. That way you can create a shared context that is used in the creation of each plugin instance. Unlike the `factory` function, the `createRootContext` function will only receive root scoped services as its dependencies, but just like the `factory` function, it can also be `async`. +Whatever value is returned by the `createRootContext` function will be shared and passed as the second argument to each invocation of the `factory` function. That way you can create a shared context that is used in the creation of each plugin instance. Unlike the `factory` function, the `createRootContext` function will only receive root scoped services as its dependencies, but just like the `factory` function, it can also be `async`. ## Default Service Factories diff --git a/docs/backend-system/architecture/04-plugins.md b/docs/backend-system/architecture/04-plugins.md index 195c32b049..af59c2a48a 100644 --- a/docs/backend-system/architecture/04-plugins.md +++ b/docs/backend-system/architecture/04-plugins.md @@ -78,4 +78,4 @@ Plugins must always be designed to be horizontally scalable. This means that you ### Isolated -Plugins must never communicate with each other directly through code, they may only communicate over the network. Plugins that wish to expose an external interface for other plugins and modules to use are recommended to do so through a [node-library](../../local-dev/cli-build-system.md#package-roles) package. The library should export an API client service to make calls to your plugin, or similar construct. +Plugins must never communicate with each other directly through code, they may only communicate over the network. Plugins that wish to expose an external interface for other plugins and modules to use are recommended to do so through a [node-library](../../tooling/cli/02-build-system.md#package-roles) package. The library should export an API client service to make calls to your plugin, or similar construct. diff --git a/docs/backend-system/building-backends/01-index.md b/docs/backend-system/building-backends/01-index.md index 4caa6fd524..44aa0c7e28 100644 --- a/docs/backend-system/building-backends/01-index.md +++ b/docs/backend-system/building-backends/01-index.md @@ -6,8 +6,12 @@ sidebar_label: Overview description: Building backends using the new backend system --- -> NOTE: If you have an existing backend that is not yet using the new backend -> system, see [migrating](./08-migrating.md). +:::note Note + +If you have an existing backend that is not yet using the new backend +system, see [migrating](./08-migrating.md). + +::: This section covers how to set up and customize your own Backstage backend. It covers some aspects of how backend instances fit into the larger system, but for a more in-depth explanation of the role of backends in the backend system, see [the architecture section](../architecture/02-backends.md). diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index 1d7e1dcd03..d38acb695e 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -201,10 +201,14 @@ const legacyPlugin = makeLegacyPlugin( After this, your backend will know how to instantiate your thing on demand and place it in the legacy plugin environment. -> NOTE: If you happen to be dealing with a service ref that does NOT have a -> default implementation, but rather has a separate service factory, then you -> will also need to import that factory and pass it to the `services` array -> argument of `createBackend`. +:::note Note + +If you happen to be dealing with a service ref that does NOT have a +default implementation, but rather has a separate service factory, then you +will also need to import that factory and pass it to the `services` array +argument of `createBackend`. + +::: ## Cleaning Up the Plugins Folder @@ -216,10 +220,14 @@ maintained by the Backstage maintainers, you may find that they have already been migrated to the new backend system. This section describes some specific such migrations you can make. -> NOTE: For each of these, note that your backend still needs to have a -> dependency (e.g. in `packages/backend/package.json`) to those plugin packages, -> and they still need to be configured properly in your app-config. Those -> mechanisms still work just the same as they used to in the old backend system. +:::note Note + +For each of these, note that your backend still needs to have a +dependency (e.g. in `packages/backend/package.json`) to those plugin packages, +and they still need to be configured properly in your app-config. Those +mechanisms still work just the same as they used to in the old backend system. + +::: ### The App Plugin @@ -452,7 +460,7 @@ catalog: /* highlight-add-end */ ``` -To migrate `GithubMultiOrgEntityProvider` and `GithubOrgEntityProvider` to the new backend system, add a reference to `@backstage/plugin-catalog-backend-module-github-org`. +To migrate `GithubMultiOrgEntityProvider` or `GithubOrgEntityProvider` to the new backend system, add a reference to `@backstage/plugin-catalog-backend-module-github-org`. ```ts title="packages/backend/src/index.ts" backend.add(import('@backstage/plugin-catalog-backend/alpha')); @@ -461,20 +469,79 @@ backend.add(import('@backstage/plugin-catalog-backend-module-github-org')); /* highlight-add-end */ ``` -If you were providing a `schedule` in code, this now needs to be set via configuration. -All other Github configuration in `app-config.yaml` remains the same. +##### GithubOrgEntityProvider + +If you were using `GithubOrgEntityProvider` you might have been configured in code like this: + +```ts title="packages/backend/src/plugins/catalog.ts" +// The org URL below needs to match a configured integrations.github entry +// specified in your app-config. +builder.addEntityProvider( + GithubOrgEntityProvider.fromConfig(env.config, { + id: 'production', + orgUrl: 'https://github.com/backstage', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }), +); +``` + +This now needs to be set via configuration. The options defined above are now set in `app-config.yaml` instead as shown below: ```yaml title="app-config.yaml" catalog: + /* highlight-add-start */ providers: githubOrg: - yourProviderId: - # ... - /* highlight-add-start */ + - id: production + githubUrl: 'https://github.com', + orgs: ['backstage'] schedule: frequency: PT30M - timeout: PT3M - /* highlight-add-end */ + timeout: PT15M + /* highlight-add-end */ +``` + +##### GithubMultiOrgEntityProvider + +If you were using `GithubMultiOrgEntityProvider` you might have been configured in code like this: + +```ts title="packages/backend/src/plugins/catalog.ts" +// The GitHub URL below needs to match a configured integrations.github entry +// specified in your app-config. +builder.addEntityProvider( + GithubMultiOrgEntityProvider.fromConfig(env.config, { + id: 'production', + githubUrl: 'https://github.com', + // Set the following to list the GitHub orgs you wish to ingest from. You can + // also omit this option to ingest all orgs accessible by your GitHub integration + orgs: ['org-a', 'org-b'], + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }), +); +``` + +This now needs to be set via configuration. The options defined above are now set in `app-config.yaml` instead as shown below: + +```yaml title="app-config.yaml" +catalog: + /* highlight-add-start */ + providers: + githubOrg: + - id: production + githubUrl: 'https://github.com', + orgs: ['org-a', 'org-b'], + schedule: + frequency: PT30M + timeout: PT15M + /* highlight-add-end */ ``` If you were providing transformers, these can be configured by extending `githubOrgEntityProviderTransformsExtensionPoint` @@ -816,12 +883,16 @@ auth: tenantId: ${AZURE_TENANT_ID} signIn: resolvers: - - resolver: emailMatchingUserEntityAnnotation - resolver: emailMatchingUserEntityProfileEmail - resolver: emailLocalPartMatchingUserEntityName + - resolver: emailMatchingUserEntityAnnotation ``` -> Note: the resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: #### Auth Plugin Modules and Their Resolvers @@ -848,7 +919,7 @@ Additional resolvers: - [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-atlassian-provider/src/resolvers.ts#L33C16-L33C46) -##### GCP IAM +##### GCP IAP (Google Identity-Aware Proxy) Setup: @@ -1078,7 +1149,11 @@ backend.add(import('@backstage/plugin-search-backend/alpha')); /* highlight-add-end */ ``` -> Note: this will use the Lunr search engine which stores its index in memory +:::note Note + +This will use the Lunr search engine which stores its index in memory. + +::: #### Search Engines @@ -1167,7 +1242,11 @@ backend.add( /* highlight-add-end */ ``` -> Note: The above example includes a default allow-all policy. If that is not what you want, do not add the second line and instead investigate one of the options below. +:::note Note + +The above example includes a default allow-all policy. If that is not what you want, do not add the second line and instead investigate one of the options below. + +::: #### Custom Permission Policy @@ -1290,7 +1369,7 @@ The vast majority of the backend plugins that currently live in the Backstage Re | @backstage/plugin-catalog-backend-module-github-org | backend-plugin-module | true | | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-github-org/README.md) | | @backstage/plugin-catalog-backend-module-gitlab | backend-plugin-module | true | true | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-gitlab/README.md) | | @backstage/plugin-catalog-backend-module-incremental-ingestion | backend-plugin-module | true | true | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-incremental-ingestion/README.md) | -| @backstage/plugin-catalog-backend-module-ldap | backend-plugin-module | | | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-ldap/README.md) | +| @backstage/plugin-catalog-backend-module-ldap | backend-plugin-module | true | | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-ldap/README.md) | | @backstage/plugin-catalog-backend-module-msgraph | backend-plugin-module | true | true | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/README.md) | | @backstage/plugin-catalog-backend-module-openapi | backend-plugin-module | true | | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-openapi/README.md) | | @backstage/plugin-catalog-backend-module-puppetdb | backend-plugin-module | true | true | [README](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-puppetdb/README.md) | diff --git a/docs/backend-system/building-plugins-and-modules/01-index.md b/docs/backend-system/building-plugins-and-modules/01-index.md index 168646afab..1aa8b140ed 100644 --- a/docs/backend-system/building-plugins-and-modules/01-index.md +++ b/docs/backend-system/building-plugins-and-modules/01-index.md @@ -73,8 +73,7 @@ items. Backend modules are used to extend [plugins](../architecture/04-plugins.md) or other modules with additional features or change existing behavior. They must always be installed in the same backend instance as the plugin or module that they extend, and may only extend a single plugin and modules from that plugin at a time. -Modules interact with their target plugin or module using the [extension -points](../architecture/05-extension-points.md) registered by the plugin, while also being +Modules interact with their target plugin or module using the [extension points](../architecture/05-extension-points.md) registered by the plugin, while also being able to depend on the [services](../architecture/03-services.md) of the target plugin. That last point is worth reiterating: injected `plugin` scoped services will be the exact @@ -157,8 +156,7 @@ the database. They will run on the same logical database instance as the target plugin, so care must be taken to choose table names that do not risk colliding with those of the plugin. A recommended naming pattern is `__`, for example the `@backstage/backend-tasks` package creates -tables named `backstage_backend_tasks__
`. If you use the default [`Knex` -migration facilities](https://knexjs.org/guide/migrations.html), you will also +tables named `backstage_backend_tasks__
`. If you use the default [`Knex` migration facilities](https://knexjs.org/guide/migrations.html), you will also want to make sure that it uses similarly prefixed migration state tables for its internal bookkeeping needs, so they do not collide with the main ones used by the plugin itself. You can do this as follows: @@ -179,8 +177,7 @@ There are several ways of configuring and customizing plugins and modules. Whenever you want to allow modules to configure your plugin dynamically, for example in the way that the catalog backend lets catalog modules inject additional entity providers, you can use the extension points mechanism. This is -described in detail with code examples in [the extension points architecture -article](../architecture/05-extension-points.md), while the following is a more +described in detail with code examples in [the extension points architecture article](../architecture/05-extension-points.md), while the following is a more slim example of how to implement an extension point for a plugin: ```ts @@ -249,7 +246,5 @@ export const examplePlugin = createBackendPlugin({ }); ``` -Before adding custom configuration options, make sure to read [the configuration -docs](../../conf/index.md), in particular the section on [defining configuration -for your own plugins](../../conf/defining.md) which explains how to establish a +Before adding custom configuration options, make sure to read [the configuration docs](../../conf/index.md), in particular the section on [defining configuration for your own plugins](../../conf/defining.md) which explains how to establish a configuration schema for your specific plugin. diff --git a/docs/backend-system/building-plugins-and-modules/02-testing.md b/docs/backend-system/building-plugins-and-modules/02-testing.md index f8af2bcabe..8a2dd0414d 100644 --- a/docs/backend-system/building-plugins-and-modules/02-testing.md +++ b/docs/backend-system/building-plugins-and-modules/02-testing.md @@ -21,8 +21,7 @@ collective term for backend [plugins](../architecture/04-plugins.md) and The function returns an HTTP server instance which can be used together with e.g. `supertest` to easily test the actual REST service surfaces of plugins who -register routes with [the HTTP router service -API](../core-services/01-index.md). +register routes with [the HTTP router service API](../core-services/01-index.md). ```ts import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 8a31251ee8..ae63b887ec 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -214,3 +214,44 @@ The above module can then be installed by the integrator alongside the kubernete backend.add(import('@backstage/plugin-kubernetes-backend')); backend.add(import('@internal/gke-cluster-supplier')); ``` + +### Dev Server + +Follow the steps below to run your migrated plugin on a local development server: + +1. First, delete the `src/run.ts` and `src/service/standaloneServer.ts` files in case they exist (the `backstage-cli` previously used these files to run legacy backend plugins locally, but they are no longer required). + +2. Next, create a new development backend in the `dev/index.ts` file. The dev server is a lite version of a backend app that is mainly used to run your plugin locally, so a simple `kubernetes` backend local development server would look like this: + +```ts title="in dev/index.js" +// This package should be installed as a `dev` dependency +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); +// Path to the file where the plugin is export as default +backend.add(import('../src')); +backend.start(); +``` + +The development server created above will be automatically configured with the default dependency factories, but if you need to mock some of the services your plugin relies on, such as the `rootConfig` service, you can use one of the `mockServices` factories: + +```ts title="in dev/index.js" +//... +// This package should be installed as `devDependecies` +import { mockServices } from '@backstage/backend-test-utils'; + +const backend = createBackend(); +// ... +backend.add( + mockServices.rootConfig.factory({ + data: { + // your config mocked values goes here + }, + }), +); +// ... +``` + +Checkout the [custom service implementations](https://backstage.io/docs/backend-system/building-backends/index#custom-service-implementations) documentation and also the [core service configurations](https://backstage.io/docs/backend-system/core-services/index) page in case you'd like to create your own custom mock factory for one or more services. + +3. Now you can finally start your plugin locally by running `yarn start` from the root folder of your plugin. diff --git a/docs/backend-system/index.md b/docs/backend-system/index.md index 22ea4c6c59..b8cf5048be 100644 --- a/docs/backend-system/index.md +++ b/docs/backend-system/index.md @@ -10,4 +10,4 @@ description: The Backend System The new backend system is released and ready for production use, and many plugins and modules have already been migrated. We recommend all plugins and deployments to migrate to the new system. -You can find an example backend setup in [the `backend-next` package](https://github.com/backstage/backstage/tree/master/packages/backend-next). +You can find an example backend setup in [the `backend` package](https://github.com/backstage/backstage/tree/master/packages/backend). diff --git a/docs/conf/reading.md b/docs/conf/reading.md index 5f7218479a..f7d1edae86 100644 --- a/docs/conf/reading.md +++ b/docs/conf/reading.md @@ -145,7 +145,7 @@ from `@backstage/core-plugin-api`. In the old backend system plugins, the configuration is passed in via options from the main backend package. See for example -[packages/backend/src/plugins/auth.ts](https://github.com/backstage/backstage/blob/244eef851f5aa19f91c7c9b5c12d5df95cf482ca/packages/backend/src/plugins/auth.ts#L23). +[packages/backend-legacy/src/plugins/auth.ts](https://github.com/backstage/backstage/blob/244eef851f5aa19f91c7c9b5c12d5df95cf482ca/packages/backend/src/plugins/auth.ts#L23). ### New Backend System diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index 791882224d..154f68c7d1 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -101,7 +101,7 @@ CMD ["node", "packages/backend", "--config", "app-config.yaml"] For more details on how the `backend:bundle` command and the `skeleton.tar.gz` file works, see the -[`backend:bundle` command docs](../local-dev/cli-commands.md#backendbundle). +[`backend:bundle` command docs](../tooling/cli/03-commands.md#backendbundle). The `Dockerfile` is located at `packages/backend/Dockerfile`, but needs to be executed with the root of the repo as the build context, in order to get access @@ -141,8 +141,12 @@ browser at `http://localhost:7007` ## Multi-stage Build -> NOTE: The `.dockerignore` is different in this setup, read on for more -> details. +:::note Note + +The `.dockerignore` is different in this setup, read on for more +details. + +::: This section describes how to set up a multi-stage Docker build that builds the entire project within Docker. This is typically slower than a host build, but is @@ -293,10 +297,14 @@ browser at `http://localhost:7007` ## Separate Frontend -> NOTE: This is an optional step, and you will lose out on the features of the -> `@backstage/plugin-app-backend` plugin. Most notably the frontend configuration -> will no longer be injected by the backend, you will instead need to use the -> correct configuration when building the frontend bundle. +:::note Note + +This is an optional step, and you will lose out on the features of the +`@backstage/plugin-app-backend` plugin. Most notably the frontend configuration +will no longer be injected by the backend, you will instead need to use the +correct configuration when building the frontend bundle. + +::: It is sometimes desirable to serve the frontend separately from the backend, either from a separate image or for example a static file serving provider. The @@ -345,8 +353,8 @@ The `Dockerfile` mentioned above located in `packages/backend` is maintained by ### Minimal Hardened Image -A contributed `Dockerfile` exists within the directory of `contrib/docker/minimal-harded-image` which uses the [`wolfi-base`](https://github.com/wolfi-dev) image to reduce vulnerabilities. When this was contributed, this alternative `Dockerfile` reduced 98.2% of vulnerabilities in the built Backstage docker image when compared with the image built from `packages/backend/Dockerfile`. +A contributed `Dockerfile` exists within the directory of `contrib/docker/minimal-hardened-image` which uses the [`wolfi-base`](https://github.com/wolfi-dev) image to reduce vulnerabilities. When this was contributed, this alternative `Dockerfile` reduced 98.2% of vulnerabilities in the built Backstage docker image when compared with the image built from `packages/backend/Dockerfile`. -To reduce maintenance, the digest of the image has been removed from the `contrib/docker/minimal-harded-image/Dockerfile` file. A complete example with the digest would be `cgr.dev/chainguard/wolfi-base:latest@sha256:3d6dece13cdb5546cd03b20e14f9af354bc1a56ab5a7b47dca3e6c1557211fcf` and it is suggested to update the `FROM` line in the `Dockerfile` to use a digest. Please do a docker pull on the image to get the latest digest. Using the digest allows tools such as Dependabot or Renovate to know exactly which image digest is being utilized and allows for Pull Requests to be triggered when a new digest is available. +To reduce maintenance, the digest of the image has been removed from the `contrib/docker/minimal-hardened-image/Dockerfile` file. A complete example with the digest would be `cgr.dev/chainguard/wolfi-base:latest@sha256:3d6dece13cdb5546cd03b20e14f9af354bc1a56ab5a7b47dca3e6c1557211fcf` and it is suggested to update the `FROM` line in the `Dockerfile` to use a digest. Please do a docker pull on the image to get the latest digest. Using the digest allows tools such as Dependabot or Renovate to know exactly which image digest is being utilized and allows for Pull Requests to be triggered when a new digest is available. It is suggested to setup Dependabot/Renovate or a similar tool to ensure the image is kept up to date so that vulnerability fixes that have been addressed are pulled in frequently. diff --git a/docs/deployment/index.md b/docs/deployment/index.md index da2c29ba23..0524e71db8 100644 --- a/docs/deployment/index.md +++ b/docs/deployment/index.md @@ -13,8 +13,12 @@ This documentation shows common examples that may be useful when deploying Backstage for the first time, or for those without established deployment practices. -> Note: The _easiest_ way to explore Backstage is to visit the -> [live demo site](https://demo.backstage.io). +:::note Note + +The _easiest_ way to explore Backstage is to visit the +[live demo site](https://demo.backstage.io). + +::: At Spotify, we deploy software generally by: diff --git a/docs/deployment/k8s.md b/docs/deployment/k8s.md index 00bf7464e3..46ba273e14 100644 --- a/docs/deployment/k8s.md +++ b/docs/deployment/k8s.md @@ -107,10 +107,14 @@ $ echo -n "backstage" | base64 YmFja3N0YWdl ``` -> Note: Secrets are base64-encoded, but not encrypted. Be sure to enable -> [Encryption at Rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) -> for the cluster. For storing secrets in Git, consider -> [SealedSecrets or other solutions](https://learnk8s.io/kubernetes-secrets-in-git). +:::note Note + +Secrets are base64-encoded, but not encrypted. Be sure to enable +[Encryption at Rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) +for the cluster. For storing secrets in Git, consider +[SealedSecrets or other solutions](https://learnk8s.io/kubernetes-secrets-in-git). + +::: The secrets can now be applied to the Kubernetes cluster: diff --git a/docs/faq/product.md b/docs/faq/product.md index 79465cf53d..edbb1ffb4d 100644 --- a/docs/faq/product.md +++ b/docs/faq/product.md @@ -37,7 +37,7 @@ more, read our blog post, Yes, we've already started releasing open source versions of some of the plugins we use here, and we'll continue to do so. -[Plugins](#what-is-a-plugin-in-backstage) are the building blocks of +[Plugins](technical.md#what-is-a-plugin-in-backstage) are the building blocks of functionality in Backstage. We have over 120 plugins inside Spotify — many of those are specialized for our use, so will remain internal and proprietary to us. But we estimate that about a third of our existing plugins make good open diff --git a/docs/faq/technical.md b/docs/faq/technical.md index ffd99dadcd..d64d81d499 100644 --- a/docs/faq/technical.md +++ b/docs/faq/technical.md @@ -154,7 +154,7 @@ maintains Backstage in your own environment. For more information, see our [Owners](https://github.com/backstage/backstage/blob/master/OWNERS.md) and -[Governance](https://github.com/backstage/backstage/blob/master/GOVERNANCE.md). +[Governance](https://github.com/backstage/community/blob/main/GOVERNANCE.md). ### Does Spotify provide a managed version of Backstage? diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 064f7c803c..0002e51160 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -198,8 +198,7 @@ in namespace `NAMESPACE` and it has adequate [permissions](#role-based-access-control), here are some sample procedures to procure a long-lived service account token for use with this provider: -- On versions of Kubernetes [prior to - 1.24](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#no-really-you-must-read-this-before-you-upgrade-1), +- On versions of Kubernetes [prior to 1.24](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#no-really-you-must-read-this-before-you-upgrade-1), you could get an (automatically-generated) token for a service account with: ```sh @@ -209,8 +208,7 @@ procure a long-lived service account token for use with this provider: | base64 --decode ``` -- For Kubernetes 1.24+, as described in [this - guide](https://kubernetes.io/docs/concepts/configuration/secret/#service-account-token-secrets), +- For Kubernetes 1.24+, as described in [this guide](https://kubernetes.io/docs/concepts/configuration/secret/#service-account-token-secrets), you can obtain a long-lived token by creating a secret: ```sh @@ -235,8 +233,7 @@ procure a long-lived service account token for use with this provider: If a cluster has `authProvider: serviceAccount` and the `serviceAccountToken` field is omitted, Backstage will ignore the configured URL and certificate data, instead attempting to access the Kubernetes API via an in-cluster client as in -[this -example](https://github.com/kubernetes-client/javascript/blob/master/examples/in-cluster.js). +[this example](https://github.com/kubernetes-client/javascript/blob/master/examples/in-cluster.js). ##### `clusters.\*.oidcTokenProvider` (optional) diff --git a/docs/features/kubernetes/installation.md b/docs/features/kubernetes/installation.md index 42ceaaa016..b3d03cc0b4 100644 --- a/docs/features/kubernetes/installation.md +++ b/docs/features/kubernetes/installation.md @@ -236,7 +236,11 @@ backend.add(kubernetesModuleCustomClusterDiscovery); backend.start(); ``` -> Note: this example assumes the `CustomClustersSupplier` class is the same from the [previous example](#custom-cluster-discovery) +:::note Note + +This example assumes the `CustomClustersSupplier` class is the same from the [previous example](#custom-cluster-discovery) + +::: ## Configuration diff --git a/docs/features/kubernetes/proxy.md b/docs/features/kubernetes/proxy.md index 5811ff8ec4..2da797d8ef 100644 --- a/docs/features/kubernetes/proxy.md +++ b/docs/features/kubernetes/proxy.md @@ -7,12 +7,10 @@ description: Interacting with the Kubernetes API in Backstage plugins [Contributors](https://backstage.io/docs/overview/glossary#backstage-user-profiles) wanting to create developer portal experiences based on data from Kubernetes (e.g. for -interacting with [Custom -Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) +interacting with [Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) beyond the default behaviors of the existing Kubernetes plugin) can leverage the Kubernetes backend plugin's proxy endpoint to allow them to make arbitrary -requests to the [REST -API](https://kubernetes.io/docs/reference/using-api/api-concepts/). +requests to the [REST API](https://kubernetes.io/docs/reference/using-api/api-concepts/). Here is a snippet fetching namespaces using the `KubernetesBackendClient` library @@ -31,8 +29,7 @@ await kubernetesApi.proxy(CLUSTER_NAME, '/api/v1/namespaces'); The proxy will interpret the [`Backstage-Kubernetes-Cluster`](https://backstage.io/docs/reference/plugin-kubernetes-backend.header_kubernetes_cluster) header as the name of the cluster to target. This name will be compared to each cluster -returned by all the configured [cluster -locators](https://backstage.io/docs/features/kubernetes/configuration#clusterlocatormethods) +returned by all the configured [cluster locators](https://backstage.io/docs/features/kubernetes/configuration#clusterlocatormethods) -- the first cluster whose [`name` field](https://backstage.io/docs/features/kubernetes/configuration#clustersname) matches the value in the header will be targeted. @@ -48,12 +45,10 @@ The proxy expects a `KubernetesAuthTranslator` to be provided that is used to de ## Authentication The proxy has no provisions for mTLS, so it cannot be used to connect to -clusters using the [x509 Client -Certs](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) +clusters using the [x509 Client Certs](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) authentication strategy.\ The current `/proxy` Implementation expects a -[Bearer -token](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#putting-a-bearer-token-in-a-request) +[Bearer token](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#putting-a-bearer-token-in-a-request) to be provided as a `Backstage-Kubernetes-Authorization` header for a target cluster. This token will be used as the `Authorization` header when forwarding a request to a target cluster. ## How to disable the proxy endpoint via PermissionPolicy @@ -64,8 +59,6 @@ This feature assumes your backstage instance has enabled the [permissions framew A sample policy like: -[packages/backend/src/plugins/permissions.ts](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/permission.ts) - ```typescript import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { @@ -106,8 +99,7 @@ even if a valid ID token was attached that a cluster would authorize. ## Other known limitations -The proxy as it was released in [Backstage -1.9](https://github.com/backstage/backstage/blob/master/docs/releases/v1.9.0-changelog.md#patch-changes-15) +The proxy as it was released in [Backstage 1.9](../../releases/v1.9.0-changelog.md#patch-changes-15) has a known bug: - [#15901](https://github.com/backstage/backstage/issues/15901) - it cannot diff --git a/docs/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md index e49bdb4fa5..6564fd0a44 100644 --- a/docs/features/search/how-to-guides.md +++ b/docs/features/search/how-to-guides.md @@ -393,7 +393,7 @@ There are other more specific search results layout components that also accept Recently, the Backstage maintainers [announced the new Backend System](https://backstage.io/blog/2023/02/15/backend-system-alpha). The search plugins are now migrated to support the new backend system. In this guide you will learn how to update your backend set up. -In "packages/backend-next/index.ts", install the search plugin [1], the search engine [2], and the search collators/decorators modules [3]: +In "packages/backend/index.ts", install the search plugin [1], the search engine [2], and the search collators/decorators modules [3]: ```ts import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; diff --git a/docs/features/search/search-engines.md b/docs/features/search/search-engines.md index d06e401847..86b6244fb6 100644 --- a/docs/features/search/search-engines.md +++ b/docs/features/search/search-engines.md @@ -34,10 +34,14 @@ const searchEngine = new LunrSearchEngine({ logger: env.logger }); const indexBuilder = new IndexBuilder({ logger: env.logger, searchEngine }); ``` -> Note: Lunr is appropriate as a zero-config search engine when developing -> other parts of Backstage locally, however its use is highly discouraged when -> running Backstage in production. When deploying Backstage, use one of the -> other search engines instead. +:::note Note + +Lunr is appropriate as a zero-config search engine when developing +other parts of Backstage locally, however its use is highly discouraged when +running Backstage in production. When deploying Backstage, use one of the +other search engines instead. + +::: ## Postgres diff --git a/docs/features/software-catalog/catalog-customization.md b/docs/features/software-catalog/catalog-customization.md index 3dc47a610a..0c8eb7bcda 100644 --- a/docs/features/software-catalog/catalog-customization.md +++ b/docs/features/software-catalog/catalog-customization.md @@ -95,7 +95,11 @@ const myColumnsFunc: CatalogTableColumnsFunc = entityListContext => { } /> ``` -> Note: the above example has been simplified and you will most likely have more code then just this in your `App.tsx` file. +:::note Note + +The above example has been simplified and you will most likely have more code then just this in your `App.tsx` file. + +::: ## Customize Actions @@ -162,7 +166,11 @@ const customActions: TableProps['actions'] = [ } /> ``` -> Note: the above example has been simplified and you will most likely have more code then just this in your `App.tsx` file. +:::note Note + +The above example has been simplified and you will most likely have more code then just this in your `App.tsx` file. + +::: The above customization will override the existing actions. Currently the only way to keep them and add your own is to also include the existing actions in your array by copying them from the [`defaultActions`](https://github.com/backstage/backstage/blob/57397e7d6d2d725712c439f4ab93f2ac6aa27bf8/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx#L113-L168). @@ -400,7 +408,11 @@ export const CustomCatalogPage = () => { The above is a very basic version of a fully custom `CatalogIndexPage`, you'll want to explore the various props to see what you can all do with them. This was built off the building blocks seen in the [`DefaultCatalogPage`](https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx) -> Note: The catalog index page is designed to have a minimal code footprint to support easy customization, but creating a replica does introduce a possibility of drifting out of date over time. Be sure to check the catalog [CHANGELOG](https://github.com/backstage/backstage/blob/master/plugins/catalog/CHANGELOG.md) periodically. +:::note Note + +The catalog index page is designed to have a minimal code footprint to support easy customization, but creating a replica does introduce a possibility of drifting out of date over time. Be sure to check the catalog [CHANGELOG](https://github.com/backstage/backstage/blob/master/plugins/catalog/CHANGELOG.md) periodically. + +::: To use this custom `CatalogIndexPage` which we called `CustomCatalogPage`, you'll need to make the following change: diff --git a/docs/features/software-catalog/extending-the-model--old.md b/docs/features/software-catalog/extending-the-model--old.md new file mode 100644 index 0000000000..7368a4a339 --- /dev/null +++ b/docs/features/software-catalog/extending-the-model--old.md @@ -0,0 +1,604 @@ +--- +id: extending-the-model--old +title: Extending the model +# prettier-ignore +description: Documentation on extending the catalog model +--- + +The Backstage catalog [entity data model](descriptor-format.md) is based on the +[Kubernetes objects format](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/), +and borrows a lot of its semantics as well. This page describes those semantics +at a higher level and how to extend them to fit your organization. + +Backstage comes with a number of catalog concepts out of the box: + +- There are a number of builtin versioned _kinds_, such as `Component`, `User` + etc. These encapsulate the high level concept of an entity, and define the + schema for its entity definition data. +- An entity has both a _metadata_ object and a _spec_ object at the root. +- Each kind may or may not have a _type_. For example, there are several well + known types of component, such as `service` and `website`. These clarify the + more detailed nature of the entity, and may affect what features are exposed + in the interface. +- Entities may have a number of _[annotations](well-known-annotations.md)_ on + them. These can be added either by humans into the descriptor files, or added + by automated processes when the entity is ingested into the catalog. +- Entities may have a number of _labels_ on them. +- Entities may have a number of _relations_, expressing how they relate to each + other in different ways. + +We'll list different possibilities for extending this below. + +## Adding a New apiVersion of an Existing Kind + +Example intents: + +> "I want to evolve this core kind, tweaking the semantics a bit so I will bump +> the apiVersion a step" + +> "This core kind is a decent fit but we want to evolve it at will so we'll move +> it to our own company's apiVersion space and use that instead of +> `backstage.io`." + +The `backstage.io` apiVersion space is reserved for use by the Backstage +maintainers. Please do not change or add versions within that space. + +If you add an [apiVersion](descriptor-format.md#apiversion-and-kind-required) +space of your own, you are effectively branching out from the underlying kind +and making your own. An entity kind is identified by the apiVersion + kind pair, +so even though the resulting entity may be similar to the core one, there will +be no guarantees that plugins will be able to parse or understand its data. See +below about adding a new kind. + +## Adding a New Kind + +Example intents: + +> "The kinds that come with the package are lacking. I want to model this other +> thing that is a poor fit for either of the builtins." + +> "This core kind is a decent fit but we want to evolve it at will so we'll move +> it to our own company's apiVersion space and use that instead of +> `backstage.io`." + +A [kind](descriptor-format.md#apiversion-and-kind-required) is an overarching +family, or an idea if you will, of entities that also share a schema. Backstage +comes with a number of builtin ones that we believe are useful for a large +variety of needs that one may want to model in Backstage. The primary ambition +is to map things to these kinds, but sometimes you may want or need to extend +beyond them. + +Introducing a new apiVersion is basically the same as adding a new kind. Bear in +mind that most plugins will be compiled against the builtin +`@backstage/catalog-model` package and have expectations that kinds align with +that. + +The catalog backend itself, from a storage and API standpoint, does not care +about the kind of entities it stores. Extending with new kinds is mainly a +matter of permitting them to pass validation when building the backend catalog +using the `CatalogBuilder`, and then to make plugins be able to understand the +new kind. + +For the consuming side, it's a different story. Adding a kind has a very large +impact. The very foundation of Backstage is to attach behavior and views and +functionality to entities that we ascribe some meaning to. There will be many +places where code checks `if (kind === 'X')` for some hard coded `X`, and casts +it to a concrete type that it imported from a package such as +`@backstage/catalog-model`. + +If you want to model something that doesn't feel like a fit for either of the +builtin kinds, feel free to reach out to the Backstage maintainers to discuss +how to best proceed. + +If you end up adding that new kind, you must namespace its `apiVersion` +accordingly with a prefix that makes sense, typically based on your organization +name - e.g. `my-company.net/v1`. Also do pick a new `kind` identifier that does +not collide with the builtin kinds. + +## Adding a New Type of an Existing Kind + +Example intents: + +> "This is clearly a component, but it's of a type that doesn't quite fit with +> the ones I've seen before." + +> "We don't call our teams "team", can't we put "flock" as the group type?" + +Some entity kinds have a `type` field in its spec. This is where an organization +are free to express the variety of entities within a kind. This field is +expected to follow some taxonomy that makes sense for yourself. The chosen value +may affect what operations and views are enabled in Backstage for that entity. +Inside Spotify our model has grown significantly over the years, and our +component types now include ML models, apps, data pipelines and many more. + +It might be tempting to put software that doesn't fit into any of the existing +types into an Other catch-all type. There are a few reasons why we advise +against this; firstly, we have found that it is preferred to match the +conceptual model that your engineers have when describing your software. +Secondly, Backstage helps your engineers manage their software by integrating +the infrastructure tooling through plugins. Different plugins are used for +managing different types of components. + +For example, the +[Lighthouse plugin](https://github.com/backstage/community-plugins/tree/main/workspaces/lighthouse/plugins/lighthouse) +only makes sense for Websites. The more specific you can be in how you model +your software, the easier it is to provide plugins that are contextual. + +Adding a new type takes relatively little effort and carries little risk. Any +type value is accepted by the catalog backend, but plugins may have to be +updated if you want particular behaviors attached to that new type. + +## Changing the Validation Rules for The Entity Envelope or Metadata Fields + +Example intents: + +> "We want to import our old catalog but the default set of allowed characters +> for a metadata.name are too strict." + +> "I want to change the rules for annotations so that I'm allowed to store any +> data in annotation values, not just strings." + +After pieces of raw entity data have been read from a location, they are passed +through a field format validation step. This ensures that the types and syntax +of the base envelope and metadata make sense - in short, things that aren't +entity-kind-specific. Some or all of these validators can be replaced when +building the backend using the catalog's dedicated `catalogModelExtensionPoint` +(or directly on the `CatalogBuilder` if you are still using the old backend +system). + +The risk and impact of this type of extension varies, based on what it is that +you want to do. For example, extending the valid character set for kinds, +namespaces and names can be fairly harmless, with a few notable exceptions - +there is code that expects these to never ever contain a colon or slash, for +example, and introducing URL-unsafe characters risks breaking plugins that +aren't careful about encoding arguments. Supporting non-strings in annotations +may be possible but has not yet been tried out in the real world - there is +likely to be some level of plugin breakage that can be hard to predict. + +You must also be careful about not making the rules _more strict_ than they used +to be after populating the catalog with data. This risks making previously valid +entities start having processing errors and fail to update. + +Before making this kind of extension, we recommend that you contact the +Backstage maintainers or a support partner to discuss your use case. + +This is an example of relaxing the format rules of the `metadata.name` field: + +```ts +import { createBackend } from '@backstage/backend-defaults'; +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { catalogModelExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; + +const myCatalogCustomizations = createBackendModule({ + pluginId: 'catalog', + moduleId: 'catalog-customization', + register(reg) { + reg.registerInit({ + deps: { + catalogModel: catalogModelExtensionPoint, + }, + async init({ catalogModel }) { + catalogModel.setFieldValidators({ + // This is only one of many methods that you can pass into + // setFieldValidators; your editor of choice should help you + // find the others. The length checks and regexp inside are + // just examples and can be adjusted as needed, but take care + // to test your changes thoroughly to ensure that you get + // them right. + isValidEntityName(value) { + return ( + typeof value === 'string' && + value.length >= 1 && + value.length <= 63 && + /^[A-Za-z0-9@+_.-]+$/.test(value) + ); + }, + }); + }, + }); + }, +}); + +const backend = createBackend(); +// ... add other backend features and the catalog backend itself here ... +backend.add(myCatalogCustomizations); +backend.start(); +``` + +## Changing the Validation Rules for Core Entity Fields + +Example intent: + +> "I don't like that the owner is mandatory. I'd like it to be optional." + +After reading and policy-checked entity data from a location, it is sent through +the processor chain looking for processors that implement the +`validateEntityKind` step, to see that the data is of a known kind and abides by +its schema. There is a builtin processor that implements this for all known core +kinds and matches the data against their fixed validation schema. This processor +can be replaced when building the backend catalog using the `CatalogBuilder`, +with a processor of your own that validates the data differently. +This replacement processor must have a name that matches the builtin processor, `BuiltinKindsEntityProcessor`. + +This type of extension is high risk, and may have high impact across the +ecosystem depending on the type of change that is made. It is therefore not +recommended in normal cases. There will be a large number of plugins and +processors - and even the core itself - that make assumptions about the shape of +the data and import the typescript data type from the `@backstage/catalog-model` +package. + +## Adding New Fields to the Metadata Object + +Example intent: + +> "Our entities have this auxiliary property that I would like to express for +> several entity kinds and it doesn't really fit as a spec field." + +The metadata object is currently left open for extension. Any unknown fields +found in the metadata will just be stored verbatim in the catalog. However we +want to caution against extending the metadata excessively. Firstly, you run the +risk of colliding with future extensions to the model. Secondly, it is common +that this type of extension lives more comfortably elsewhere - primarily in the +metadata labels or annotations, but sometimes you even may want to make a new +component type or similar instead. + +There are some situations where metadata can be the right place. If you feel +that you have run into such a case and that it would apply to others, do feel +free to contact the Backstage maintainers or a support partner to discuss your +use case. Maybe we can extend the core model to benefit both you and others. + +## Adding New Fields to the Spec Object of an Existing Kind + +Example intent: + +> "The builtin Component kind is fine but we want to add an additional field to +> the spec for describing whether it's in prod or staging." + +A kind's schema validation typically doesn't forbid "unknown" fields in an +entity `spec`, and the catalog will happily store whatever is in it. So doing +this will usually work from the catalog's point of view. + +Adding fields like this is subject to the same risks as mentioned about metadata +extensions above. Firstly, you run the risk of colliding with future extensions +to the model. Secondly, it is common that this type of extension lives more +comfortably elsewhere - primarily in the metadata labels or annotations, but +sometimes you even may want to make a new component type or similar instead. + +There are some situations where the spec can be the right place. If you feel +that you have run into such a case and that it would apply to others, do feel +free to contact the Backstage maintainers or a support partner to discuss your +use case. Maybe we can extend the core model to benefit both you and others. + +## Adding a New Annotation + +Example intents: + +> "Our custom made build system has the concept of a named pipeline-set, and we +> want to associate individual components with their corresponding pipeline-sets +> so we can show their build status." + +> "We have an alerting system that automatically monitors service health, and +> there's this integration key that binds the service to an alerts pool. We want +> to be able to show the ongoing alerts for our services in Backstage so it'd be +> nice to attach that integration key to the entity somehow." + +Annotations are mainly intended to be consumed by plugins, for feature detection +or linking into external systems. Sometimes they are added by humans, but often +they are automatically generated at ingestion time by processors. There is a set +of [well-known annotations](well-known-annotations.md), but you are free to add +additional ones. This carries no risk or impact to other systems as long as you +abide by the following naming rules. + +- The `backstage.io` annotation prefix is reserved for use by the Backstage + maintainers. Reach out to us if you feel that you would like to make an + addition to that prefix. +- Annotations that pertain to a well known third party system should ideally be + prefixed with a domain, in a way that makes sense to a reader and connects it + clearly to the system (or the maker of the system). For example, you might use + a `pagerduty.com` prefix for pagerduty related annotations, but maybe not + `ldap.com` for LDAP annotations since it's not directly affiliated with or + owned by an LDAP foundation/company/similar. +- Annotations that have no prefix at all, are considered local to your Backstage + instance and can be used freely as such, but you should not make use of them + outside of your organization. For example, if you were to open source a plugin + that generates or consumes annotations, then those annotations must be + properly prefixed with your company domain or a domain that pertains to the + annotation at hand. + +## Adding a New Label + +Example intents: + +> "Our process reaping system wants to periodically scrape for components that +> have a certain property." + +> "It'd be nice if our service owners could just tag their components somehow to +> let the CD system know to automatically generate SRV records or not for that +> service." + +Labels are mainly intended to be used for filtering of entities, by external +systems that want to find entities that have some certain property. This is +sometimes used for feature detection / selection. An example could be to add a +label `deployments.my-company.net/register-srv: "true"`. + +At the time of writing this, the use of labels is very limited and we are still +settling together with the community on how to best use them. If you feel that +your use case fits the labels best, we would appreciate if you let the Backstage +maintainers know. + +You are free to add labels. This carries no risk or impact to other systems as +long as you abide by the following naming rules. + +- The `backstage.io` label prefix is reserved for use by the Backstage + maintainers. Reach out to us if you feel that you would like to make an + addition to that prefix. +- Labels that pertain to a well known third party system should ideally be + prefixed with a domain, in a way that makes sense to a reader and connects it + clearly to the system (or the maker of the system). For example, you might use + a `pagerduty.com` prefix for pagerduty related labels, but maybe not + `ldap.com` for LDAP labels since it's not directly affiliated with or owned by + an LDAP foundation/company/similar. +- Labels that have no prefix at all, are considered local to your Backstage + instance and can be used freely as such, but you should not make use of them + outside of your organization. For example, if you were to open source a plugin + that generates or consumes labels, then those labels must be properly prefixed + with your company domain or a domain that pertains to the label at hand. + +## Adding a New Relation Type + +Example intents: + +> "We have this concept of service maintainership, separate from ownership, that +> we would like to make relations to individual users for." + +> "We feel that we want to explicitly model the team-to-global-department +> mapping as a relation, because it is core to our org setup and we frequently +> query for it." + +Any processor can emit relations for entities as they are being processed, and +new processors can be added when building the backend catalog using the +`CatalogBuilder`. They can emit relations based on the entity data itself, or +based on information gathered from elsewhere. Relations are directed and go from +a source entity to a target entity. They are also tied to the entity that +originated them - the one that was subject to processing when the relation was +emitted. Relations may be dangling (referencing something that does not actually +exist by that name in the catalog), and callers need to be aware of that. + +There is a set of [well-known relations](well-known-relations.md), but you are +free to emit your own as well. You cannot change the fact that they are directed +and have a source and target that have to be an +[entity reference](references.md), but you can invent your own types. You do not +have to make any changes to the catalog backend in order to accept new relation +types. + +At the time of writing this, we do not have any namespacing/prefixing scheme for +relation types. The type is also not validated to contain only some particular +set of characters. Until rules for this are settled, you should stick to using +only letters, dashes and digits, and to avoid collisions with future core +relation types, you may want to prefix the type somehow. For example: +`myCompany-maintainerOf` + `myCompany-maintainedBy`. + +If you have a suggestion for a relation type to be elevated to the core +offering, reach out to the Backstage maintainers or a support partner. + +## Using a Well-Known Relation Type for a New Purpose + +Example intents: + +> "The ownerOf/ownedBy relation types sound like a good fit for expressing how +> users are technical owners of our company specific ServiceAccount kind, and we +> want to reuse those relation types for that." + +At the time of writing, this is uncharted territory. If the documented use of a +relation states that one end of the relation commonly is a User or a Group, for +example, then consumers are likely to have conditional statements on the form +`if (x.kind === 'User') {} else {}`, which get confused when an unexpected kind +appears. + +If you want to extend the use of an established relation type in a way that has +an effect outside of your organization, reach out to the Backstage maintainers +or a support partner to discuss risk/impact. It may even be that one end of the +relation could be considered for addition to the core. + +## Adding a New Status field + +Example intent: + +> "We would like to convey entity statuses through the catalog in a generic way, +> as an integration layer. Our monitoring and alerting system has a plugin with +> Backstage, and it would be useful if the entity's status field contained the +> current alert state close to the actual entity data for anyone to consume. We +> find the `status.items` semantics a poor fit, so we would prefer to make our +> own custom field under `status` for these purposes." + +We have not yet ventured to define any generic semantics for the `status` +object. We recommend sticking with the `status.items` mechanism where possible +(see below), since third party consumers will not be able to consume your status +information otherwise. Please reach out to the maintainers on Discord or by +making a GitHub issue describing your use case if you are interested in this +topic. + +## Adding a New Status Item Type + +Example intent: + +> "The semantics of the entity `status.items` field are fine for our needs, but +> we want to contribute our own type of status into that array instead of the +> catalog specific one." + +This is a simple, low risk way of adding your own status information to +entities. Consumers will be able to easily track and display the status together +with other types / sources. + +We recommend that any status type that are not strictly private within the +organization be namespaced to avoid collisions. Statuses emitted by Backstage +core processes will for example be prefixed with `backstage.io/`, your +organization may prefix with `my-org.net/`, and `pagerduty.com/active-alerts` +could be a sensible complete status item type for that particular external +system. + +The mechanics for how to emit custom statuses is not in place yet, so if this is +of interest to you, you might consider contacting the maintainers on Discord or +my making a GitHub issue describing your use case. +[This issue](https://github.com/backstage/backstage/issues/2292) also contains +more context. + +## Referencing different environments with the model + +Example intent: + +> "I have multiple versions of my API deployed in different environments so I +> want to have `mytool-dev` and `mytool-prod` as different entities." + +While it's possible to have different versions of the same thing represented as +separate entities, it's something we generally recommend against. We believe +that a developer should be able to just find for example one `Component` +representing a service, and to be able to see the different code versions that +are deployed throughout your stack within its view. This reasoning works +similarly for other kinds as well, such as `API`. + +That being said - sometimes the differences between versions are so large, that +they represent what is for all intents and purposes an entirely new entity as +seen from the consumer's point of view. This can happen for example for +different _significant_ major versions of an API, and in particular if the two +major versions coexist in the ecosystem for some time. In those cases, it can be +motivated to have one `my-api-v2` and one `my-api-v3` named entity. This matches +the end user's expectations when searching for the API, and matches the desire +to maybe have separate documentation for the two and similar. But use this +sparingly - only do it if the extra modelling burden is outweighed by any +potential better clarity for users. + +When writing your custom plugins, we encourage designing them such that they can +show all the different variations through environments etc under one canonical +reference to your software in the catalog. For example for a continuous +deployment plugin, a user is likely to be greatly helped by being able to see +the entity's versions deployed in all different environments next to each other +in one view. That is also where they might be offered the ability to promote +from one environment to the other, do rollbacks, see their relative performance +metrics, and similar. This coherency and collection of tooling in one place is +where something like Backstage can offer the most value and effectiveness of +use. Splitting your entities apart into small islands makes this harder. + +## Implementing custom model extensions + +This section walks you through the steps involved extending the catalog model +with a new Entity type. + +### Creating a custom entity definition + +The first step of introducing a custom entity is to define what shape and schema +it has. We do this using a TypeScript type, as well as a JSONSchema schema. + +Most of the time you will want to have at least the TypeScript type of your +extension available in both frontend and backend code, which means you likely +want to have an isomorphic package that houses these types. Within the Backstage +main repo the package naming pattern of `-common` is used for isomorphic +packages, and you may choose to adopt this pattern as well. + +You can generate an isomorphic plugin package by running:`yarn new --select plugin-common` +or you can run `yarn new` and then select "plugin-common" from the list of options + +There's at this point no existing templates for generating isomorphic plugins +using the `@backstage/cli`. Perhaps the simplest way to get started right now is +to copy the contents of one of the existing packages in the main repository, +such as `plugins/scaffolder-common`, and rename the folder and file contents to +the desired name. This example uses _foobar_ as the plugin name so the plugin +will be named _foobar-common_. + +Once you have a common package in place you can start adding your own entity +definitions. For the exact details on how to do that we defer to getting +inspired by the existing +[scaffolder-common](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-common/src/index.ts) +package. But in short you will need to declare a TypeScript type and a +JSONSchema for the new entity kind. + +### Building a custom processor for the entity + +The next step is to create a custom processor for your new entity kind. This +will be used within the catalog to make sure that it's able to ingest and +validate entities of our new kind. Just like with the definition package, you +can find inspiration in for example the existing +[ScaffolderEntitiesProcessor](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-scaffolder-entity-model/src/processor/ScaffolderEntitiesProcessor.ts). +We also provide a high-level example of what a catalog process for a custom +entity might look like: + +```ts +import { CatalogProcessor, CatalogProcessorEmit, processingResult } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common' +import { Entity, entityKindSchemaValidator } from '@backstage/catalog-model'; + +// For an example of the JSONSchema format and how to use $ref markers to the +// base definitions, see: +// https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema/kinds/Component.v1alpha1.schema.json +import { foobarEntityV1alpha1Schema } from '@internal/catalog-model'; + +export class FoobarEntitiesProcessor implements CatalogProcessor { + // You often end up wanting to support multiple versions of your kind as you + // iterate on the definition, so we keep each version inside this array as a + // convenient pattern. + private readonly validators = [ + // This is where we use the JSONSchema that we export from our isomorphic + // package + entityKindSchemaValidator(foobarEntityV1alpha1Schema), + ]; + + // Return processor name + getProcessorName(): string { + return 'FoobarEntitiesProcessor' + } + + // validateEntityKind is responsible for signaling to the catalog processing + // engine that this entity is valid and should therefore be submitted for + // further processing. + async validateEntityKind(entity: Entity): Promise { + for (const validator of this.validators) { + // If the validator throws an exception, the entity will be marked as + // invalid. + if (validator(entity)) { + return true; + } + } + + // Returning false signals that we don't know what this is, passing the + // responsibility to other processors to try to validate it instead. + return false; + } + + async postProcessEntity( + entity: Entity, + _location: LocationSpec, + emit: CatalogProcessorEmit, + ): Promise { + if ( + entity.apiVersion === 'example.com/v1alpha1' && + entity.kind === 'Foobar' + ) { + const foobarEntity = entity as FoobarEntityV1alpha1; + + // Typically you will want to emit any relations associated with the + // entity here. + emit(processingResult.relation({ ... })) + } + + return entity; + } +} +``` + +Once the processor is created it can be wired up to the catalog via the +`CatalogBuilder` in `packages/backend/src/plugins/catalog.ts`: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { FoobarEntitiesProcessor } from '@internal/plugin-foobar-backend'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + /* highlight-add-next-line */ + builder.addProcessor(new FoobarEntitiesProcessor()); + const { processingEngine, router } = await builder.build(); + // .. +} +``` diff --git a/docs/features/software-catalog/extending-the-model.md b/docs/features/software-catalog/extending-the-model.md index b3d7de3a65..51acd44c1d 100644 --- a/docs/features/software-catalog/extending-the-model.md +++ b/docs/features/software-catalog/extending-the-model.md @@ -519,6 +519,9 @@ will be used within the catalog to make sure that it's able to ingest and validate entities of our new kind. Just like with the definition package, you can find inspiration in for example the existing [ScaffolderEntitiesProcessor](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-scaffolder-entity-model/src/processor/ScaffolderEntitiesProcessor.ts). + +The custom processor should be created as a separate module for the catalog plugin. For information on how to set that up, see the [plugin docs](../../plugins/backend-plugin.md#creating-a-backend-plugin). Use `yarn new --select backend-module` instead to create a module. For our case, the module ID will be `foobar` and the plugin ID will be `catalog`. + We also provide a high-level example of what a catalog process for a custom entity might look like: @@ -585,20 +588,43 @@ export class FoobarEntitiesProcessor implements CatalogProcessor { } ``` -Once the processor is created it can be wired up to the catalog via the -`CatalogBuilder` in `packages/backend/src/plugins/catalog.ts`: +#### New Backend -```ts title="packages/backend/src/plugins/catalog.ts" +To use your custom processor, you'll need to add the module to your backend as well as integrate your module with the catalog plugin. + +```ts title="plugins/catalog-backend-module-foobar/src/index.ts" +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { catalogModelExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; /* highlight-add-next-line */ -import { FoobarEntitiesProcessor } from '@internal/plugin-foobar-backend'; +import { FoobarEntitiesProcessor } from './providers'; -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - /* highlight-add-next-line */ - builder.addProcessor(new FoobarEntitiesProcessor()); - const { processingEngine, router } = await builder.build(); - // .. -} +export const catalogModuleFoobarEntitiesProcessor = createBackendModule({ + pluginId: 'catalog', + moduleId: 'foobar', + register(env) { + env.registerInit({ + deps: { + catalog: catalogProcessingExtensionPoint, + }, + async init({ catalog }) { + catalog.addProcessor(new FoobarEntitiesProcessor()); + }, + }); + }, +}); + +export default catalogModuleFoobarEntitiesProcessor; ``` + +This module can then be installed to your backend like so, + +```ts +backend.add(import('@internal/plugin-catalog-backend-module-foobar')); +``` + +#### Legacy Backend + +Look through the [legacy documentation](./extending-the-model--old.md). diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index a1dcbabb99..6eaee2f80d 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -55,7 +55,7 @@ Some defining traits of entity providers: The recommended way of instantiating the catalog backend classes is to use the `CatalogBuilder`, as illustrated in the -[example backend here](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/catalog.ts). +[example backend here](https://github.com/backstage/backstage/blob/master/packages/backend-legacy/src/plugins/catalog.ts). We will create a new [`EntityProvider`](https://github.com/backstage/backstage/blob/master/plugins/catalog-node/src/api/provider.ts) subclass that can be added to this catalog builder. @@ -531,7 +531,7 @@ does so! The recommended way of instantiating the catalog backend classes is to use the `CatalogBuilder`, as illustrated in the -[example backend here](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/catalog.ts). +[example backend here](https://github.com/backstage/backstage/blob/master/packages/backend-legacy/src/plugins/catalog.ts). We will create a new [`CatalogProcessor`](https://github.com/backstage/backstage/blob/master/plugins/catalog-node/src/api/processor.ts) subclass that can be added to this catalog builder. diff --git a/docs/features/software-catalog/index.md b/docs/features/software-catalog/index.md index c98d6911b4..a65bfb4a44 100644 --- a/docs/features/software-catalog/index.md +++ b/docs/features/software-catalog/index.md @@ -40,8 +40,7 @@ browse the catalog at `http://localhost:3000`. ## Adding components to the catalog -The source of truth for the components in your software catalog are [metadata -YAML files](descriptor-format.md) stored in source control (GitHub, GitHub +The source of truth for the components in your software catalog are [metadata YAML files](descriptor-format.md) stored in source control (GitHub, GitHub Enterprise, GitLab, ...). Repositories can include one or multiple metadata files. Usually the metadata file is located in the repository root. This is not a formal requirement & metadata files can be placed anywhere in the repository. diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index d1c01141e4..13fe496fc1 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -162,9 +162,13 @@ steps and merging them into the final object which is what is visible from the catalog API. As the final entity itself gets updated, the stitcher makes sure that the search table gets refreshed accordingly as well. -> Note: The search table mentioned here is not related to the core Search -> feature of Backstage. It's rather the table that backs the ability to filter -> catalog API query results. +:::note Note + +The search table mentioned here is not related to the core Search +feature of Backstage. It's rather the table that backs the ability to filter +catalog API query results. + +::: ![Stitching overview](../../assets/features/catalog/life-of-an-entity_stitching.svg) diff --git a/docs/features/software-catalog/system-model.md b/docs/features/software-catalog/system-model.md index af359bb18a..ee7270a960 100644 --- a/docs/features/software-catalog/system-model.md +++ b/docs/features/software-catalog/system-model.md @@ -120,6 +120,9 @@ product or use-case, share the same entity types in their APIs, and integrate well with each other. Other domains could be “Content Ingestion”, “Ads” or “Search”. +In case of a large organization, it might make sense to further group domains +in a hierarchy, where a domain can be a subdomain of another domain. + ## Other ### Location diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index 6396d7530a..083516192c 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -86,12 +86,17 @@ contains more information about the required fields. Once we have a `template.yaml` ready, we can then add it to the software catalog for use by the scaffolder. -> Note: When you add or modify a template, you will need to refresh the location entity. -> Otherwise, Backstage won't display the template in the available templates, -> or it will keep showing the old template. You can refresh the location instance by -> going into `Catalog` web page, choosing `Locations` instead of `Components`, and selecting the correct location entity. -> From there, you can click on the refresh icon representing "Scheduled entity refresh" action. -> Afterwards, you should see your template updated. +:::note Note + +When you add or modify a template, you will need to refresh the location entity. +Otherwise, Backstage won't display the template in the available templates, +or it will keep showing the old template. You can refresh the location instance by +going into `Catalog` web page, choosing `Locations` instead of `Components`, and selecting the correct +location entity. +From there, you can click on the refresh icon representing "Scheduled entity refresh" action. +Afterwards, you should see your template updated. + +::: You can add the template files to the catalog through [static location configuration](../software-catalog/configuration.md#static-location-configuration), diff --git a/docs/features/software-templates/authorizing-parameters-steps-and-actions.md b/docs/features/software-templates/authorizing-scaffolder-template-details.md similarity index 74% rename from docs/features/software-templates/authorizing-parameters-steps-and-actions.md rename to docs/features/software-templates/authorizing-scaffolder-template-details.md index 072f750a14..127677757c 100644 --- a/docs/features/software-templates/authorizing-parameters-steps-and-actions.md +++ b/docs/features/software-templates/authorizing-scaffolder-template-details.md @@ -1,10 +1,10 @@ --- -id: authorizing-parameters-steps-and-actions -title: 'Authorizing parameters, steps and actions' -description: How to authorize part of a template +id: authorizing-scaffolder-template-details +title: 'Authorizing scaffolder tasks, parameters, steps, and actions' +description: How to authorize parts of a template and authorize scaffolder task access --- -The scaffolder plugin integrates with the Backstage [permission framework](../../permissions/overview.md), which allows you to control access to certain parameters and steps in your templates based on the user executing the template. +The scaffolder plugin integrates with the Backstage [permission framework](../../permissions/overview.md), which allows you to control access to certain parameters and steps in your templates based on the user executing the template. It also allows you to control access to scaffolder tasks. ### Authorizing parameters and steps @@ -174,7 +174,64 @@ class ExamplePermissionPolicy implements PermissionPolicy { } ``` -Although the rules exported by the scaffolder are simple, combining them can help you achieve more complex cases. +### Authorizing scaffolder tasks + +The scaffolder plugin also exposes permissions that can restrict access to tasks, task logs, task creation, and task cancellation. This can be useful if you want to control who has access to these areas of the scaffolder. + +```ts title="packages/src/backend/plugins/permissions.ts" +/* highlight-add-start */ +import { + taskCancelPermission, + taskCreatePermission, + taskReadPermission, +} from '@backstage/plugin-scaffolder-common/alpha'; +/* highlight-add-end */ + +class ExamplePermissionPolicy implements PermissionPolicy { + async handle( + request: PolicyQuery, + user?: BackstageIdentityResponse, + ): Promise { + /* highlight-add-start */ + if (isPermission(request.permission, taskCreatePermission)) { + if (user?.identity.userEntityRef === 'user:default/spiderman') { + return { + result: AuthorizeResult.ALLOW, + }; + } + } + if (isPermission(request.permission, taskCancelPermission)) { + if (user?.identity.userEntityRef === 'user:default/spiderman') { + return { + result: AuthorizeResult.ALLOW, + }; + } + } + if (isPermission(request.permission, taskReadPermission)) { + if (user?.identity.userEntityRef === 'user:default/spiderman') { + return { + result: AuthorizeResult.ALLOW, + }; + } + } + /* highlight-add-end */ + + return { + result: AuthorizeResult.DENY, + }; + } +} +``` + +In the provided example permission policy, we only grant the `spiderman` user permissions to perform/access the following actions/resources: + +- Read all scaffolder tasks and their associated events/logs. +- Cancel any ongoing scaffolder tasks. +- Trigger software templates, which effectively creates new scaffolder tasks. + +Any other user would be denied access to these actions/resources. + +Although the rules exported by the scaffolder are simple, combining them can help you achieve more complex use cases. ### Authorizing in the New Backend System @@ -229,4 +286,8 @@ backend.add(customPermissionBackendModule); /* highlight-add-end */ ``` -> Note: the `ExamplePermissionPolicy` here could be the one from the [Authorizing parameters and steps](#authorizing-parameters-and-steps) example or from the [Authorizing actions](#authorizing-actions) example. It would work the same way for both of them. +:::note Note + +The `ExamplePermissionPolicy` here could be the one from the [Authorizing parameters and steps](#authorizing-parameters-and-steps) example or from the [Authorizing actions](#authorizing-actions) example. It would work the same way for both of them. + +::: diff --git a/docs/features/software-templates/builtin-actions.md b/docs/features/software-templates/builtin-actions.md index 94b2d2298b..5b1e4347da 100644 --- a/docs/features/software-templates/builtin-actions.md +++ b/docs/features/software-templates/builtin-actions.md @@ -57,7 +57,11 @@ backend.add(import('@backstage/plugin-scaffolder-backend-module-github')); backend.start(); ``` -> Note: This is a simplified example of what your backend may look like, you may have more code in here then this. +:::note Note + +This is a simplified example of what your backend may look like, you may have more code in here then this. + +::: ## Listing Actions diff --git a/docs/features/software-templates/configuration.md b/docs/features/software-templates/configuration.md index 24b8c530b8..571f1150d0 100644 --- a/docs/features/software-templates/configuration.md +++ b/docs/features/software-templates/configuration.md @@ -12,7 +12,11 @@ This is done in your `app-config.yaml` by adding [Backstage integrations](https://backstage.io/docs/integrations/) for the appropriate source code repository for your organization. -> Note: Integrations may already be set up as part of your `app-config.yaml`. +:::note Note + +Integrations may already be set up as part of your `app-config.yaml`. + +::: The next step is to [add templates](http://backstage.io/docs/features/software-templates/adding-templates) to your Backstage app. diff --git a/docs/features/software-templates/index.md b/docs/features/software-templates/index.md index d0c1bea9b2..d4fa6ac971 100644 --- a/docs/features/software-templates/index.md +++ b/docs/features/software-templates/index.md @@ -20,10 +20,14 @@ locations like GitHub or GitLab. > Be sure to have covered > [Getting Started with Backstage](../../getting-started) before proceeding. -> Note: if you're running Backstage with Node 20 or later, you'll need to pass the flag `--no-node-snapshot` to Node in order to -> use the templates feature. -> One way to do this is to specify the `NODE_OPTIONS` environment variable before starting Backstage: -> `export NODE_OPTIONS=--no-node-snapshot` +:::note Note + +If you're running Backstage with Node 20 or later, you'll need to pass the flag `--no-node-snapshot` to Node in order to +use the templates feature. +One way to do this is to specify the `NODE_OPTIONS` environment variable before starting Backstage: +`export NODE_OPTIONS=--no-node-snapshot` + +::: The Software Templates are available under `/create`. For local development you should be able to reach them at `http://localhost:3000/create`. @@ -103,3 +107,17 @@ from `backstage/packages/app/src/App.tsx`: ``` After the change, you should no longer see the button. + +## Previewing and Executing Previous Template Tasks + +Each execution of a template is treated as a unique task, identifiable by its own unique ID. To view a list of previously executed template tasks, navigate to the "Create" page and access the "Task List" from the context menu (represented by the vertical ellipsis, or 'kebab menu', icon in the upper right corner). + +![Template Task List](../../assets/software-templates/template-task-list.png) + +If you wish to re-run a previously executed template, navigate to the template tasks page. Locate the desired task and select the "Start Over" option from the context menu. + +![Template Start Over](../../assets/software-templates/template-start-over.png) + +This action will initiate a new execution of the selected template, pre-populated with the same parameters as the previous run, but these parameters can be edited before re-execution. + +In the event of a failed template execution, the "Start Over" option can be used to re-execute the template. The parameters from the original run will be pre-filled, but they can be adjusted as needed before retrying the template. diff --git a/docs/features/software-templates/migrating-to-rjsf-v5.md b/docs/features/software-templates/migrating-to-rjsf-v5.md index 829aaf8410..856841bdd4 100644 --- a/docs/features/software-templates/migrating-to-rjsf-v5.md +++ b/docs/features/software-templates/migrating-to-rjsf-v5.md @@ -5,7 +5,11 @@ title: 'Migrating to react-jsonschema-form@v5' description: Docs on migrating to `react-jsonschema-form`@v5 and the new designs --- -> Note: If you were previously using the `/alpha` imports to test out the `scaffolder/next` work, those imports have been promoted to the default exports from the respective packages. You should just have to remove the `/alpha` from the import path, and remove the `Next` from the import name. `NextScaffolderPage` -> `ScaffolderPage`, `createNextScaffolderFieldExtension` -> `createScaffolderFieldExtension` etc. +:::note Note + +If you were previously using the `/alpha` imports to test out the `scaffolder/next` work, those imports have been promoted to the default exports from the respective packages. You should just have to remove the `/alpha` from the import path, and remove the `Next` from the import name. `NextScaffolderPage` -> `ScaffolderPage`, `createNextScaffolderFieldExtension` -> `createScaffolderFieldExtension` etc. + +::: ## What's `react-jsonschema-form`? diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index c1386786c7..dd5667b7b1 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -8,10 +8,14 @@ If you want to extend the functionality of the Scaffolder, you can do so by writing custom actions which can be used alongside our [built-in actions](./builtin-actions.md). -> Note: When adding custom actions, the actions array will **replace the -> built-in actions too**. Meaning, you will no longer be able to use them. -> If you want to continue using the builtin actions, include them in the actions -> array when registering your custom actions, as seen below. +:::note Note + +When adding custom actions, the actions array will **replace the +built-in actions too**. Meaning, you will no longer be able to use them. +If you want to continue using the builtin actions, include them in the actions +array when registering your custom actions, as seen below. + +::: ## Writing your Custom Action diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index d8e6feb559..15591eeb67 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -681,6 +681,8 @@ how to use them in the Scaffolder templates. It's important to mention that Back native filters from the Nunjucks library. For a complete list of these native filters and their usage, refer to the [Nunjucks documentation](https://mozilla.github.io/nunjucks/templating.html#builtin-filters). +To create your own custom filters, look to the section [Custom Filters](#custom-filters) hereafter. + ### parseRepoUrl The `parseRepoUrl` filter parse a repository URL into @@ -765,3 +767,150 @@ The `projectSlug` filter generates a project slug from a repository URL - **Input**: `github.com?repo=backstage&org=backstage` - **Output**: `backstage/backstage` + +## Custom Filters + +Whenever it is needed to extend the built-in filters with yours `${{ parameters.name | my-filter1 | my-filter2 | etc }}`, then you can add them +using the property `additionalTemplateFilters`. + +The `additionalTemplateFilters` property accepts as type a `Record` + +```ts title="plugins/scaffolder-backend/src/service/Router.ts" + additionalTemplateFilters?: Record; +``` + +where the first parameter is the name of the filter and the second receives a list of `JSON value` arguments. The `templateFilter()` function must return a JsonValue which is either a Json array, object or primitive. + +```ts title="plugins/scaffolder-node/src/types.ts" +export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined; +``` + +From a practical coding point of view, you will translate that into the following snippet code handling 2 filters: + +```ts" +... +additionalTemplateFilters: { + base64: (...args: JsonValue[]) => btoa(args.join("")), + betterFilter: (...args: JsonValue[]) => { return `This is a much better string than "${args}", don't you think?` } +} +``` + +And within your template, you will be able to use the filters using a parameter and the filter passed using the pipe symbol + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: test + title: Test +spec: + owner: user:guest + type: service + + parameters: + - title: Test custom filters + properties: + userName: + title: Name of the user + type: string + + steps: + - id: debug + name: debug + action: debug:log + input: + message: ${{ parameters.userName | betterFilter | base64 }} +``` + +Next, you will have to register the property `addTemplateFilters` using the `scaffolderTemplatingExtensionPoint` of a new `BackendModule` [created](../../backend-system/architecture/06-modules.md). + +Here is a very simplified example of how to do that: + +```ts title="packages/backend-next/src/index.ts" +/* highlight-add-start */ +import { scaffolderTemplatingExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; +import { createBackendModule } from '@backstage/backend-plugin-api'; +/* highlight-add-end */ + +/* highlight-add-start */ +const scaffolderModuleCustomFilters = createBackendModule({ + pluginId: 'scaffolder', // name of the plugin that the module is targeting + moduleId: 'custom-filters', + register(env) { + env.registerInit({ + deps: { + scaffolder: scaffolderTemplatingExtensionPoint, + // ... and other dependencies as needed + }, + async init({ scaffolder /* ..., other dependencies */ }) { + scaffolder.addTemplateFilters({ + base64: (...args: JsonValue[]) => btoa(args.join('')), + betterFilter: (...args: JsonValue[]) => { + return `This is a much better string than "${args}", don't you think?`; + }, + }); + }, + }); + }, +}); +/* highlight-add-end */ + +const backend = createBackend(); +backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); +/* highlight-add-next-line */ +backend.add(scaffolderModuleCustomFilters()); +``` + +If you still use the legacy backend system, then you will use the `createRouter()` function of the `Scaffolder plugin` + +```ts title="packages/backend/src/plugins/scaffolder.ts" +export default async function createPlugin({ + logger, + config, +}: PluginEnvironment): Promise { + ... + return await createRouter({ + logger, + config, + + additionalTemplateFilters: { + + } + }); +``` + +## Template Editor + +Writing template is most of the times an iterative process. You will need to test your template to make sure it has a good user experience and that it works as expected. To help on this process the scaffolder comes with a build in template editor that allows you to test your template in a real environment for querying data and execute the actions on dry-run mode to see the results of those one. + +To access to the template editor you can go to the templates page and select "Template Editor" from the context menu or navigate to the `{scaffolder-path}/edit` url. (i.e. the default route would be `/create/edit`) + +![Context menu](../../assets/software-templates/context-menu.png) + +The template editor has 3 main sections: + +1. **Load Template Directory**: Load a local template directory, allowing you to both edit and try executing your own template. +2. **Edit Template Form**: Preview and edit a template form, either using a sample template or by loading a template from the catalog. +3. **Custom Field Explorer**: View and play around with available installed custom field extensions. + +### Load Template Directory + +Allow to load a directory on your local file system that contains a template and editing the files in it while previewing the form and executing the template. + +![template editor load dir](../../assets/software-templates/template-editor-load-dir.png) + +If you complete the form in the right side and click on `Create` button, the template will be executed in dry-run mode and the result will be shown in the `Dry-run result` drawer that will pop-up at the bottom of the screen. + +Here we could find all the file system results of the template execution as well as the logs of each action that was executed. + +![dry run drawer example](../../assets/software-templates/template-editor-dry-run.png) + +### Edit Template Form + +This is a reduced version of the template editor that allows you to select any template from the catalog and do some modifications on the form presented to the user to test some changes. + +Have in mind that changes in this form will not be saved on the template and is meant to test out changes to replicate them manually on the template file after. + +### Custom Field Explorer + +The custom filed explorer allows you to select any custom field loaded on the backstage instance and test different values and configurations. diff --git a/docs/features/techdocs/architecture.md b/docs/features/techdocs/architecture.md index 2cb8543ccd..8c9c4401cc 100644 --- a/docs/features/techdocs/architecture.md +++ b/docs/features/techdocs/architecture.md @@ -13,9 +13,14 @@ out-of-the box experience. ![TechDocs Architecture diagram](../../assets/techdocs/architecture-basic.drawio.svg) -> Note: See below for our recommended deployment architecture which takes care -> of stability, scalability and speed. Also look at the -> [HOW TO migrate guide](how-to-guides.md#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach). +:::note Note + +See below for our recommended deployment architecture which takes care +of stability, scalability and speed. Also look at the +[HOW TO migrate guide](how-to-guides +md#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach). + +::: When you open a TechDocs site in Backstage, the [TechDocs Reader](./concepts.md#techdocs-reader) makes a request to diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index bf55c90af9..6cbbc83614 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -219,7 +219,11 @@ backend.add(import('@backstage/plugin-techdocs-backend/alpha')); backend.start(); ``` -> Note: The above is a very simplified example, you may have more content then this in your version. +:::note Note + +The above is a very simplified example, you may have more content then this in your version. + +::: ## Setting the configuration diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md index b25c2a3928..3a7cfd97bb 100644 --- a/docs/features/techdocs/how-to-guides.md +++ b/docs/features/techdocs/how-to-guides.md @@ -499,8 +499,12 @@ Start writing your documentation by adding more markdown (.md) files to this folder (/docs) or replace the content in this file. ``` -> Note: The values of `site_name`, `component_id` and `site_description` depends -> on how you have configured your `template.yaml` +:::note Note + +The values of `site_name`, `component_id` and `site_description` depends +on how you have configured your `template.yaml`. + +::: Done! You now have support for TechDocs in your own software template! @@ -514,7 +518,11 @@ theme: font: false ``` -> Note: The addition `name: material` is necessary. Otherwise it will not work +:::note Note + +The addition `name: material` is necessary. Otherwise it will not work + +::: ## How to enable iframes in TechDocs @@ -623,12 +631,16 @@ plugins: - kroki ``` -> Note: you will very likely want to set a `kroki` `ServerURL` configuration in your -> `mkdocs.yml` as well. The default value is the publicly hosted `kroki.io`. If -> you have sensitive information in your organization's diagrams, you should set -> up a [server of your own](https://docs.kroki.io/kroki/setup/install/) and use it -> instead. Check out [mkdocs-kroki-plugin config](https://github.com/AVATEAM-IT-SYSTEMHAUS/mkdocs-kroki-plugin#config) -> for more plugin configuration details. +:::note Note + +You will very likely want to set a `kroki` `ServerURL` configuration in your +`mkdocs.yml` as well. The default value is the publicly hosted `kroki.io`. If +you have sensitive information in your organization's diagrams, you should set +up a [server of your own](https://docs.kroki.io/kroki/setup/install/) and use it +instead. Check out [mkdocs-kroki-plugin config](https://github.com/AVATEAM-IT-SYSTEMHAUS/mkdocs-kroki-plugin#config) +for more plugin configuration details. + +::: 4. **Add mermaid code into TechDocs:** @@ -766,7 +778,11 @@ backend.add(techdocsCustomBuildStrategy()); backend.start(); ``` -> Note: You may need to add the `@backstage/plugin-techdocs-node` package to your backend `package.json` if it's not been imported already. +:::note Note + +You may need to add the `@backstage/plugin-techdocs-node` package to your backend `package.json` if it's not been imported already. + +::: ## How to use other mkdocs plugins? diff --git a/docs/features/techdocs/using-cloud-storage.md b/docs/features/techdocs/using-cloud-storage.md index aaf2758241..6ba826ea62 100644 --- a/docs/features/techdocs/using-cloud-storage.md +++ b/docs/features/techdocs/using-cloud-storage.md @@ -169,17 +169,21 @@ permissions to: - `s3:ListBucket` - To retrieve bucket metadata - `s3:GetObject` - To retrieve files from the bucket -> Note: If you need to migrate documentation objects from an older-style path -> format including case-sensitive entity metadata, you will need to add some -> additional permissions to be able to perform the migration, including: -> -> - `s3:PutBucketAcl` (for copying files, -> [more info here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html)) -> - `s3:DeleteObject` and `s3:DeleteObjectVersion` (for deleting migrated files, -> [more info here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html)) -> -> ...And you will need to ensure the permissions apply to the bucket itself, as -> well as all resources under the bucket. See the example policy below. +:::note Note + +If you need to migrate documentation objects from an older-style path +format including case-sensitive entity metadata, you will need to add some +additional permissions to be able to perform the migration, including: + +- `s3:PutBucketAcl` (for copying files, + [more info here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html)) +- `s3:DeleteObject` and `s3:DeleteObjectVersion` (for deleting migrated files, + [more info here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html)) + +...And you will need to ensure the permissions apply to the bucket itself, as +well as all resources under the bucket. See the example policy below. + +::: ```json { diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 21028627bc..41702e6823 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -22,10 +22,10 @@ In order to override an app extension, you must create a new extension and add i In the example below, we create a file that exports custom extensions for the app's `light` and `dark` themes: -```tsx title="packages/app/src/themes.ts" +```tsx title="packages/app/src/themes.tsx" import { createThemeExtension, - createExtensionOverrides + createExtensionOverrides, } from '@backstage/frontend-plugin-api'; import { apertureThemes } from './themes'; import { ApertureLightIcon, ApertureDarkIcon } from './icons'; @@ -59,8 +59,8 @@ const apertureDarkTheme = createThemeExtension({ }); // Creating an extension overrides preset -export createExtensionOverrides({ - extensions: [apertureLightTheme, apertureDarkTheme] +export default createExtensionOverrides({ + extensions: [apertureLightTheme, apertureDarkTheme], }); ``` @@ -96,8 +96,11 @@ We recommend that plugin developers share the extension IDs in their plugin docu Imagine you have a plugin with the ID `'search'`, and the plugin provides a page extension that you want to fully override with your own custom component. To do so, you need to create your page extension with an explicit `namespace` option that matches that of the plugin that you want to override, in this case `'search'`. If the existing extension also has an explicit `name` you'd need to set the `name` of your override extension to the same value as well. -```tsx title="packages/app/src/search.ts" -import { createPageExtension } from '@backstage/frontend-plugin-api'; +```tsx title="packages/app/src/search.tsx" +import { + createPageExtension, + createExtensionOverrides, +} from '@backstage/frontend-plugin-api'; // Creating a custom search page extension const customSearchPage = createPageExtension({ @@ -108,7 +111,7 @@ const customSearchPage = createPageExtension({ loader: () => import('./SearchPage').then(m => m.), }); -export createExtensionOverrides({ +export default createExtensionOverrides({ extensions: [customSearchPage] }); ``` @@ -137,7 +140,7 @@ Sometimes you just need to quickly create a new extension and not overwrite an a Imagine you want to create a page that is currently only used by your application, like an Institutional page, for example. You can use overrides to extend the Backstage app to render it. To do so, simply create a page extension and pass it to the app as an override: -```tsx title="packages/app/src/App.ts" +```tsx title="packages/app/src/App.tsx" import { createApp } from '@backstage/frontend-app-api'; import { createPageExtension, diff --git a/docs/frontend-system/building-apps/02-configuring-extensions.md b/docs/frontend-system/building-apps/02-configuring-extensions.md index 2fd4ce69fc..4052ef47f0 100644 --- a/docs/frontend-system/building-apps/02-configuring-extensions.md +++ b/docs/frontend-system/building-apps/02-configuring-extensions.md @@ -6,4 +6,50 @@ sidebar_label: Configuring Extensions description: Documentation for how to configure extensions in a Backstage app --- -TODO +All extensions in a Backstage app can be configured through static configuration. This configuration is all done under the `app.extensions` configuration key. For more general information on how to write configuration for Backstage, see the section on [writing configuration](../../conf/writing.md). + +## Extension Configuration Schema + +This section focuses on the format of the `app.extensions` configuration and the various shorthands that are available. + +The most complete and verbose format for configuring an individual extensions is as follows: + +```yaml +app: + extensions: + - : + attachTo: + id: + input: + disabled: + config: +``` + +All of the top-level fields are optional: `attachTo`, `disabled`, and `config`. Every extension implementation must provide defaults for all of these fields that will be used if they are not provided in the configuration. + +Note that `app.extensions` is always an array rather than an object. For example, the following is invalid: + +```yaml title="INVALID" +app: + extensions: + : # Invalid, this should be an array item, `app.extensions` is now an object + config: ... +``` + +In addition to this schema, there are a number of shorthands available: + +Rather than a full object, you can specify just the ID of the extension as a string. This is equivalent to setting `disabled` to `false`: + +```yaml +app: + extensions: + - ‘’ +``` + +You can enable/disable individual extension by ID, in this case the value is a boolean: + +```yaml +app: + extensions: + - : +``` diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md index 937e865133..0abdd2aac3 100644 --- a/docs/frontend-system/building-apps/08-migrating.md +++ b/docs/frontend-system/building-apps/08-migrating.md @@ -117,7 +117,7 @@ You can then also add any additional extensions that you may need to create as p [Utility API](../utility-apis/01-index.md) factories are now installed as extensions instead. Pass the existing factory to `createApiExtension` and install it in the app. For more information, see the section on [configuring Utility APIs](../utility-apis/04-configuring.md). -For example, the following API configuration: +For example, the following `apis` configuration: ```ts const app = createApp({ @@ -151,15 +151,75 @@ Icons are currently installed through the usual options to `createApp`, but will Plugins are now passed through the `features` options instead. +For example, the following `plugins` configuration: + +```tsx +import { homePlugin } from '@backstage/plugin-home'; + +createApp({ + // ... + plugins: [homePlugin], + // ... +}); +``` + +Can be converted to the following `features` configuration: + +```tsx +// plugins are now default exported via alpha subpath +import homePlugin from '@backstage/plugin-home/alpha'; + +createApp({ + // ... + features: [homePlugin], + // ... +}); +``` + +Plugins don't even have to be imported manually after installing their package if [features discovery](../architecture/02-app.md#feature-discovery) is enabled. + +```yaml title="in app-config.yaml" +app: + # Enabling plugin and override features discovery + experimental: 'all' +``` + ### `featureFlags` Declaring features flags in the app is no longer supported, move these declarations to the appropriate plugins instead. +For example, the following app feature flags configuration: + +```tsx +createApp({ + // ... + featureFlags: [ + { + pluginId: '', + name: 'tech-radar', + description: 'Enables the tech radar plugin', + }, + ], + // ... +}); +``` + +Can be converted to the following plugin configuration: + +```tsx +createPlugin({ + id: 'tech-radar', + // ... + featureFlags: [{ name: 'tech-radar' }], + // ... +}); +``` + ### `components` Many app components are now installed as extensions instead using `createComponentExtension`. See the section on [configuring app components](./01-index.md#configure-your-app) for more information. -The `Router` component is now a built-in extension that you can override using `createRouterExtension`. +The `Router` component is now a built-in extension that you can [override](../architecture/05-extension-overrides.md) using `createRouterExtension`. The Sign-in page is now installed as an extension using the `createSignInPageExtension` instead. @@ -277,6 +337,35 @@ const app = createApp({ Translations are now installed as extensions, using `createTranslationExtension`. +For example, the following translations configuration: + +```tsx +import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; +createApp({ + // ... + __experimentalTranslations: { + resources: [ + createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), + ], + }, + // ... +}); +``` + +Can be converted to the following extension: + +```tsx +createTranslationExtension({ + resource: createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), +}); +``` + ## Gradual Migration After updating all `createApp` options as well as using `convertLegacyApp` to use your existing app structure, you should be able to start up the app and see that it still works. If that is not the case, make sure you read any error messages that you may see in the app as they can provide hints on what you need to fix. If you are still stuck, you can check if anyone else ran into the same issue in our [GitHub issues](https://github.com/backstage/backstage/issues), or ask for help in our [community Discord](https://discord.gg/backstage-687207715902193673). @@ -368,7 +457,7 @@ The entity pages are typically defined in `packages/app/src/components/catalog` New apps feature a built-in sidebar extension (`app/nav`) that will render all nav item extensions provided by plugins. This is a placeholder implementation and not intended as a long-term solution. In the future we will aim to provide a more flexible sidebar extension that allows for more customization out of the box. -Because the built-in sidebar is quite limited you may want to override the sidebar with your own custom implementation. To do so, use `createExtension` directly and refer to the [original sidebar implementation](https://github.com/backstage/backstage/blob/master/packages/frontend-app-api/src/extensions/AppNav.tsx). The following is an example of how to take your existing sidebar from the `Root` component that you typically find in `packages/app/src/components/Root.tsx`, and use it in an extension override: +Because the built-in sidebar is quite limited you may want to override the sidebar with your own custom implementation. To do so, use `createExtension` directly and refer to the [original sidebar implementation](https://github.com/backstage/backstage/blob/master/packages/frontend-app-api/src/extensions/AppNav.tsx). The following is an example of how to take your existing sidebar from the `Root` component that you typically find in `packages/app/src/components/Root.tsx`, and use it in an [extension override](../architecture/05-extension-overrides.md): ```tsx const nav = createExtension({ @@ -435,3 +524,24 @@ export default app.createRoot( ``` Any app root wrapper needs to be migrated to be an extension, using `createAppRootWrapperExtension`. Note that if you have multiple wrappers they must be completely independent of each other, i.e. the order in which they the appear in the React tree should not matter. If that is not the case then you should group them into a single wrapper. + +Here is an example converting the `CustomAppBarrier` into extension: + +```tsx +createApp({ + // ... + features: [ + createExtensionOverrides({ + extensions: [ + createAppRootWrapperExtension({ + name: 'CustomAppBarrier', + // Whenever your component uses legacy core packages, wrap it with "compatWrapper" + // e.g. props => compatWrapper() + Component: CustomAppBarrier, + }), + ], + }), + ], + // ... +}); +``` diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index 8aadeaf19a..3fb0365ad0 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -28,7 +28,11 @@ export const myTheme = createUnifiedTheme({ }); ``` -> Note: we recommend creating a `theme` folder in `packages/app/src` to place your theme file to keep things nicely organized. +:::note Note + +we recommend creating a `theme` folder in `packages/app/src` to place your theme file to keep things nicely organized. + +::: You can also create a theme from scratch that matches the `BackstageTheme` type exported by [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme). See the [Material UI docs on theming](https://material-ui.com/customization/theming/) for more information about how that can be done. @@ -504,7 +508,11 @@ You can add more icons, if the [default icons](https://github.com/backstage/back You might want to use this method if you have an icon you want to use in several locations. -Note: If the icon is not available as one of the default icons or one you've added then it will fall back to Material UI's `LanguageIcon` +:::note Note + +If the icon is not available as one of the default icons or one you've added then it will fall back to Material UI's `LanguageIcon` + +::: ## Custom Sidebar diff --git a/docs/getting-started/keeping-backstage-updated.md b/docs/getting-started/keeping-backstage-updated.md index e7324f4603..1de8874d56 100644 --- a/docs/getting-started/keeping-backstage-updated.md +++ b/docs/getting-started/keeping-backstage-updated.md @@ -13,7 +13,7 @@ starting point that's meant to be evolved. The Backstage CLI has a command to bump all `@backstage` packages and dependencies you're using to the latest versions: -[versions:bump](https://backstage.io/docs/local-dev/cli-commands#versionsbump). +[versions:bump](https://backstage.io/docs/tooling/cli/03-commands#versionsbump). ```bash yarn backstage-cli versions:bump @@ -70,7 +70,7 @@ example, depends on global referential equality. This can cause problems in Backstage with API lookup, or config loading. To help resolve these situations, the Backstage CLI has -[versions:check](https://backstage.io/docs/local-dev/cli-commands#versionscheck). This +[versions:check](https://backstage.io/docs/tooling/cli/03-commands#versionscheck). This will validate versions of `@backstage` packages in your app to check for duplicate definitions: diff --git a/docs/integrations/azure/discovery--old.md b/docs/integrations/azure/discovery--old.md new file mode 100644 index 0000000000..be490d70fe --- /dev/null +++ b/docs/integrations/azure/discovery--old.md @@ -0,0 +1,187 @@ +--- +id: discovery--old +title: Azure DevOps Discovery +sidebar_label: Discovery +# prettier-ignore +description: Automatically discovering catalog entities from repositories in an Azure DevOps organization +--- + +:::info +This documentation is written for the old backend which has been replaced by [the new backend system](../../backend-system/index.md), being the default since Backstage [version 1.24](../../releases/v1.24.0.md). If have migrated to the new backend system, you may want to read [its own article](./discovery.md) instead. Otherwise, [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + +The Azure DevOps integration has a special entity provider for discovering +catalog entities within an Azure DevOps. The provider will crawl your Azure +DevOps organization and register entities matching the configured path. This can +be useful as an alternative to static locations or manually adding things to the +catalog. + +This guide explains how to install and configure the Azure DevOps Entity Provider (recommended) or the Azure DevOps Processor. + +## Dependencies + +### Code Search Feature + +Azure discovery is driven by the Code Search feature in Azure DevOps, this may not be enabled by default. For Azure +DevOps Services you can confirm this by looking at the installed extensions in your Organization Settings. For Azure +DevOps Server you'll find this information in your Collection Settings. + +If the Code Search extension is not listed then you can install it from the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=ms.vss-code-search&targetId=f9352dac-ba6e-434e-9241-a848a510ce3f&utm_source=vstsproduct&utm_medium=SearchExtStatus). + +### Azure Integration + +Setup [Azure integration](locations.md) with `host` and `token`. Host must be `dev.azure.com` for Cloud users, otherwise set this to your on-premise hostname. + +## Installation + +At your configuration, you add one or more provider configs: + +```yaml title="app-config.yaml" +catalog: + providers: + azureDevOps: + yourProviderId: # identifies your dataset / provider independent of config changes + organization: myorg + project: myproject + repository: service-* # this will match all repos starting with service-* + path: /catalog-info.yaml + schedule: # optional; same options as in TaskScheduleDefinition + # supports cron, ISO duration, "human duration" as used in code + frequency: { minutes: 30 } + # supports ISO duration, "human duration" as used in code + timeout: { minutes: 3 } + yourSecondProviderId: # identifies your dataset / provider independent of config changes + organization: myorg + project: '*' # this will match all projects + repository: '*' # this will match all repos + path: /catalog-info.yaml + anotherProviderId: # another identifier + organization: myorg + project: myproject + repository: '*' # this will match all repos + path: /src/*/catalog-info.yaml # this will search for files deep inside the /src folder + yetAnotherProviderId: # guess, what? Another one :) + host: selfhostedazure.yourcompany.com + organization: myorg + project: myproject + branch: development +``` + +The parameters available are: + +- **`host:`** _(optional)_ Leave empty for Cloud hosted, otherwise set to your self-hosted instance host. +- **`organization:`** Your Organization slug (or Collection for on-premise users). Required. +- **`project:`** _(required)_ Your project slug. Wildcards are supported as shown on the examples above. Using '\*' will search all projects. For a project name containing spaces, use both single and double quotes as in `project: '"My Project Name"'`. +- **`repository:`** _(optional)_ The repository name. Wildcards are supported as show on the examples above. If not set, all repositories will be searched. +- **`path:`** _(optional)_ Where to find catalog-info.yaml files. Defaults to /catalog-info.yaml. +- **`branch:`** _(optional)_ The branch name to use. +- **`schedule`**: + - **`frequency`**: + How often you want the task to run. The system does its best to avoid overlapping invocations. + - **`timeout`**: + The maximum amount of time that a single task invocation can take. + - **`initialDelay`** _(optional)_: + The amount of time that should pass before the first invocation happens. + - **`scope`** _(optional)_: + `'global'` or `'local'`. Sets the scope of concurrency control. + +_Note:_ + +- The path parameter follows the same rules as the search on Azure DevOps web interface. For more details visit the [official search documentation](https://docs.microsoft.com/en-us/azure/devops/project/search/get-started-search?view=azure-devops). +- To use branch parameters, it is necessary that the desired branch be added to the "Searchable branches" list within Azure DevOps Repositories. To do this, follow the instructions below: + +1. Access your Azure DevOps and open the repository in which you want to add the branch. +2. Click on "Settings" in the lower-left corner of the screen. +3. Select the "Options" option in the left navigation bar. +4. In the "Searchable branches" section, click on the "Add" button to add a new branch. +5. In the window that appears, enter the name of the branch you want to add and click "Add". +6. The added branch will now appear in the "Searchable branches" list. + +It may take some time before the branch is indexed and searchable. + +As this provider is not one of the default providers, you will first need to install +the Azure catalog plugin: + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure +``` + +Once you've done that, you'll also need to add the segment below to `packages/backend/src/plugins/catalog.ts`: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { AzureDevOpsEntityProvider } from '@backstage/plugin-catalog-backend-module-azure'; + +const builder = await CatalogBuilder.create(env); +/** ... other processors and/or providers ... */ +/* highlight-add-start */ +builder.addEntityProvider( + AzureDevOpsEntityProvider.fromConfig(env.config, { + logger: env.logger, + // optional: alternatively, use scheduler with schedule defined in app-config.yaml + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // optional: alternatively, use schedule + scheduler: env.scheduler, + }), +); +/* highlight-add-end */ +``` + +## Alternative Processor + +As an alternative to the entity provider `AzureDevOpsEntityProvider`, you can still use the `AzureDevopsDiscoveryProcessor`. + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { AzureDevOpsDiscoveryProcessor } from '@backstage/plugin-catalog-backend-module-azure'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + /* highlight-add-next-line */ + builder.addProcessor( + AzureDevOpsDiscoveryProcessor.fromConfig(env.config, { + logger: env.logger, + }), + ); + + // .. +} +``` + +```yaml +catalog: + locations: + # Scan all repositories for a catalog-info.yaml in the root of the default branch + - type: azure-discovery + target: https://dev.azure.com/myorg/myproject + # Or use a custom pattern for a subset of all repositories with default repository + - type: azure-discovery + target: https://dev.azure.com/myorg/myproject/_git/service-* + # Or use a custom file format and location + - type: azure-discovery + target: https://dev.azure.com/myorg/myproject/_git/*?path=/src/*/catalog-info.yaml + # And optionally provide a specific branch name using the version parameter + - type: azure-discovery + target: https://dev.azure.com/myorg/myproject/_git/*?path=/catalog-info.yaml&version=GBtopic/catalog-info +``` + +Note the `azure-discovery` type, as this is not a regular `url` processor. + +When using a custom pattern, the target is composed of these parts: + +- The base instance URL, `https://dev.azure.com` in this case +- The organization name which is required, `myorg` in this case +- The project name which is optional, `myproject` in this case. This defaults to \*, which scans all the projects where the token has access to. +- The repository blob to scan, which accepts \* wildcard tokens and must be + added after `_git/`. This can simply be `*` to scan all repositories in the + project. +- The path within each repository to find the catalog YAML file. This will + usually be `/catalog-info.yaml`, `/src/*/catalog-info.yaml` or a similar + variation for catalog files stored in the root directory of each repository. +- The repository branch to scan which is optional, `topic/catalog-info` in this case. If omitted, the repo's default branch will be scanned. The `GB` prefix is required, as this is how Azure DevOps identifies the version as a branch. diff --git a/docs/integrations/azure/discovery.md b/docs/integrations/azure/discovery.md index 7fbba5228d..7e7b465118 100644 --- a/docs/integrations/azure/discovery.md +++ b/docs/integrations/azure/discovery.md @@ -6,6 +6,10 @@ sidebar_label: Discovery description: Automatically discovering catalog entities from repositories in an Azure DevOps organization --- +:::info +This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./discovery--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + The Azure DevOps integration has a special entity provider for discovering catalog entities within an Azure DevOps. The provider will crawl your Azure DevOps organization and register entities matching the configured path. This can @@ -30,7 +34,7 @@ Setup [Azure integration](locations.md) with `host` and `token`. Host must be `d ## Installation -At your configuration, you add one or more provider configs: +In your configuration, you add one or more provider configs: ```yaml title="app-config.yaml" catalog: @@ -103,81 +107,11 @@ the Azure catalog plugin: yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure ``` -Once you've done that, you'll also need to add the segment below to `packages/backend/src/plugins/catalog.ts`: +Then updated your backend by adding the following line: -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-next-line */ -import { AzureDevOpsEntityProvider } from '@backstage/plugin-catalog-backend-module-azure'; - -const builder = await CatalogBuilder.create(env); -/** ... other processors and/or providers ... */ +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend/alpha')); /* highlight-add-start */ -builder.addEntityProvider( - AzureDevOpsEntityProvider.fromConfig(env.config, { - logger: env.logger, - // optional: alternatively, use scheduler with schedule defined in app-config.yaml - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 30 }, - timeout: { minutes: 3 }, - }), - // optional: alternatively, use schedule - scheduler: env.scheduler, - }), -); +backend.add(import('@backstage/plugin-catalog-backend-module-azure/alpha')); /* highlight-add-end */ ``` - -## Alternative Processor - -As an alternative to the entity provider `AzureDevOpsEntityProvider`, you can still use the `AzureDevopsDiscoveryProcessor`. - -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-next-line */ -import { AzureDevOpsDiscoveryProcessor } from '@backstage/plugin-catalog-backend-module-azure'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - /* highlight-add-next-line */ - builder.addProcessor( - AzureDevOpsDiscoveryProcessor.fromConfig(env.config, { - logger: env.logger, - }), - ); - - // .. -} -``` - -```yaml -catalog: - locations: - # Scan all repositories for a catalog-info.yaml in the root of the default branch - - type: azure-discovery - target: https://dev.azure.com/myorg/myproject - # Or use a custom pattern for a subset of all repositories with default repository - - type: azure-discovery - target: https://dev.azure.com/myorg/myproject/_git/service-* - # Or use a custom file format and location - - type: azure-discovery - target: https://dev.azure.com/myorg/myproject/_git/*?path=/src/*/catalog-info.yaml - # And optionally provide a specific branch name using the version parameter - - type: azure-discovery - target: https://dev.azure.com/myorg/myproject/_git/*?path=/catalog-info.yaml&version=GBtopic/catalog-info -``` - -Note the `azure-discovery` type, as this is not a regular `url` processor. - -When using a custom pattern, the target is composed of these parts: - -- The base instance URL, `https://dev.azure.com` in this case -- The organization name which is required, `myorg` in this case -- The project name which is optional, `myproject` in this case. This defaults to \*, which scans all the projects where the token has access to. -- The repository blob to scan, which accepts \* wildcard tokens and must be - added after `_git/`. This can simply be `*` to scan all repositories in the - project. -- The path within each repository to find the catalog YAML file. This will - usually be `/catalog-info.yaml`, `/src/*/catalog-info.yaml` or a similar - variation for catalog files stored in the root directory of each repository. -- The repository branch to scan which is optional, `topic/catalog-info` in this case. If omitted, the repo's default branch will be scanned. The `GB` prefix is required, as this is how Azure DevOps identifies the version as a branch. diff --git a/docs/integrations/azure/locations.md b/docs/integrations/azure/locations.md index b59c4149e0..ddc95b65eb 100644 --- a/docs/integrations/azure/locations.md +++ b/docs/integrations/azure/locations.md @@ -68,11 +68,15 @@ integrations: If you do not specify the `organizations` field the credential will be used for all organizations for which no other credential is configured. -> Note: An Azure DevOps provider is added automatically at startup for -> convenience, so you only need to list it if you want to supply a -> [personalAccessToken](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate), -> a [service principal](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity), -> or a [managed identity](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity) +:::note Note + +An Azure DevOps provider is added automatically at startup for +convenience, so you only need to list it if you want to supply a +[personalAccessToken](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate), +a [service principal](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity), +or a [managed identity](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity) + +::: The configuration is a structure with these elements: @@ -86,9 +90,11 @@ The `credentials` element is a structure with these elements: - `tenantId`: The tenant ID of the service principal (required for service principal) - `personalAccessToken`: The personal access token (required for personal access token) -> Note: -> -> - You cannot use a service principal or managed identity for Azure DevOps Server (on-premises) organizations -> - You can only use a service principal or managed identity for Microsoft Entra ID (formerly Azure Active Directory) backed Azure DevOps organizations -> - You can only specify one credential per host without any organizations specified -> - The personal access token should just be provided as the raw token generated by Azure DevOps using the format `raw_token` with no base64 encoding. Formatting and base64'ing is handled by dependent libraries handling the Azure DevOps API +:::note Note + +- You cannot use a service principal or managed identity for Azure DevOps Server (on-premises) organizations +- You can only use a service principal or managed identity for Microsoft Entra ID (formerly Azure Active Directory) backed Azure DevOps organizations +- You can only specify one credential per host without any organizations specified +- The personal access token should just be provided as the raw token generated by Azure DevOps using the format `raw_token` with no base64 encoding. Formatting and base64'ing is handled by dependent libraries handling the Azure DevOps API + +::: diff --git a/docs/integrations/azure/org--old.md b/docs/integrations/azure/org--old.md new file mode 100644 index 0000000000..13d53b24b3 --- /dev/null +++ b/docs/integrations/azure/org--old.md @@ -0,0 +1,274 @@ +--- +id: org--old +title: Microsoft Entra Tenant Data +sidebar_label: Org Data +# prettier-ignore +description: Importing users and groups from Microsoft Entra ID into Backstage +--- + +:::info +This documentation is written for the old backend which has been replaced by [the new backend system](../../backend-system/index.md), being the default since Backstage [version 1.24](../../releases/v1.24.0.md). If have migrated to the new backend system, you may want to read [its own article](./org.md) instead.Otherwise, [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + +The Backstage catalog can be set up to ingest organizational data - users and +teams - directly from a tenant in Microsoft Entra ID via the +Microsoft Graph API. + +## Installation + +The package is not installed by default, therefore you have to add `@backstage/plugin-catalog-backend-module-msgraph` to your backend package. + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-msgraph +``` + +Next add the basic configuration to `app-config.yaml` + +```yaml title="app-config.yaml" +catalog: + providers: + microsoftGraphOrg: + default: + tenantId: ${AZURE_TENANT_ID} + user: + filter: accountEnabled eq true and userType eq 'member' + group: + filter: > + securityEnabled eq false + and mailEnabled eq true + and groupTypes/any(c:c+eq+'Unified') + schedule: + frequency: PT1H + timeout: PT50M +``` + +Finally, register the plugin in `catalog.ts`. +For large organizations, this plugin can take a long time, so be careful setting low frequency / timeouts and importing a large amount of users / groups for the first try. + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { MicrosoftGraphOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-msgraph'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + /* highlight-add-start */ + builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + logger: env.logger, + scheduler: env.scheduler, + }), + ); + /* highlight-add-end */ + + // .. +} +``` + +## Authenticating with Microsoft Graph + +### Local Development + +For a local dev environment, it's recommended you have the Azure CLI or Azure PowerShell installed, and are logged in to those. +Alternatively you can use VSCode with the Azure extension if you install `@azure/identity-vscode`. +When these are set up, the plugin will authenticate with the Microsoft Graph API without you needing to configure any credentials, or granting any special permissions. +If you can't do this, you'll have to create an App Registration. + +### App Registration + +If none of the other authentication methods work, you can create an app registration in the azure portal. +By default the graph plugin requires the following Application permissions (not Delegated) for Microsoft Graph: + +- `GroupMember.Read.All` +- `User.Read.All` + +If your organization required Admin Consent for these permissions, that will need to be granted. + +When authenticating with a ClientId/ClientSecret, you can either set the `AZURE_TENANT_ID`, `AZURE_CLIENT_ID` and `AZURE_CLIENT_SECRET` environment variables, or specify the values in configuration + +```yaml +microsoftGraphOrg: + default: + ##... + clientId: 9ef1aac6-b454-4e69-9cf5-7199df049281 + clientSecret: REDACTED +``` + +To authenticate with a certificate rather than a client secret, you can set the `AZURE_TENANT_ID`, `AZURE_CLIENT_ID` and `AZURE_CLIENT_CERTIFICATE_PATH` environments + +### Managed Identity + +If deploying to resources that supports Managed Identity, and has identities configured (e.g. Azure App Services, Azure Container Apps), Managed Identity should be picked up without any additional configuration. +If your app has multiple managed identities, you may need to set the `AZURE_CLIENT_ID` environment variable to tell Azure Identity which identity to use. + +To grant the managed identity the same permissions as mentioned in _App Registration_ above, [please follow this guide](https://docs.microsoft.com/en-us/azure/app-service/tutorial-connect-app-access-microsoft-graph-as-app-javascript?tabs=azure-powershell) + +## Filtering imported Users and Groups + +By default, the plugin will import all users and groups from your directory. +This can be customized through [filters](https://learn.microsoft.com/en-us/graph/filter-query-parameter) and [search](https://learn.microsoft.com/en-us/graph/search-query-parameter) queries. Keep in mind that if you omit filters and search queries for the user or group properties, the plugin will automatically import all available users or groups. + +### Groups + +A smaller set of groups can be obtained by configuring a search query or a filter. +If both `filter` and `search` are provided, then groups must match both to be ingested. + +```yaml +microsoftGraphOrg: + providerId: + group: + filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified') + search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' +``` + +In addition to these groups, one additional group will be created for your organization. +All imported groups will be a child of this group. + +### Users + +There are two modes for importing users - You can import all user objects matching a `filter`. + +```yaml +microsoftGraphOrg: + providerId: + user: + filter: accountEnabled eq true and userType eq 'member' +``` + +Alternatively you can import users that are members of specific groups. +For each group matching the `search` and `filter` query, each group member will be imported. +Only direct group members will be imported, not transient users. + +```yaml +microsoftGraphOrg: + providerId: + userGroupMember: + filter: "displayName eq 'Backstage Users'" + search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' +``` + +### User photos + +By default, the photos of users will be fetched and added to each user entity. For huge organizations this may be unfeasible, as it will take a _very_ long time, and can be disabled by setting `loadPhotos` to `false`: + +```yaml +microsoftGraphOrg: + providerId: + user: + filter: ... + loadPhotos: false +``` + +## Customizing Transformation + +Ingested entities can be customized by providing custom transformers. +These can be used to completely replace the built in logic, or used to tweak it by using the default transformers (`defaultGroupTransformer`, `defaultUserTransformer` and `defaultOrganizationTransformer` +Entities can also be excluded from backstage by returning `undefined`. + +These Transformers are be registered when configuring `MicrosoftGraphOrgEntityProvider` + +```ts +builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + // ... + /* highlight-add-start */ + groupTransformer: myGroupTransformer, + userTransformer: myUserTransformer, + organizationTransformer: myOrganizationTransformer, + /* highlight-add-end */ + }), +); +``` + +When using custom transformers, you may want to customize the data returned. +Several configuration options can be provided to tweak the Microsoft Graph query to get the data you need + +```yaml +microsoftGraphOrg: + providerId: + user: + expand: manager + group: + expand: member + select: ['id', 'displayName', 'description'] +``` + +The following provides an example of each kind of transformer + +```ts +import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; +import { + defaultGroupTransformer, + defaultUserTransformer, + defaultOrganizationTransformer, +} from '@backstage/plugin-catalog-backend-module-msgraph'; +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; + +// This group transformer completely replaces the built in logic with custom logic. +export async function myGroupTransformer( + group: MicrosoftGraph.Group, + groupPhoto?: string, +): Promise { + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: group.id!, + annotations: {}, + }, + spec: { + type: 'Microsoft Entra ID', + children: [], + }, + }; +} + +// This user transformer makes use of the built in logic, but also sets the description field +export async function myUserTransformer( + graphUser: MicrosoftGraph.User, + userPhoto?: string, +): Promise { + const backstageUser = await defaultUserTransformer(graphUser, userPhoto); + + if (backstageUser) { + backstageUser.metadata.description = 'Loaded from Microsoft Entra ID'; + } + + return backstageUser; +} + +// Example organization transformer that removes the organization group completely +export async function myOrganizationTransformer( + graphOrganization: MicrosoftGraph.Organization, +): Promise { + return undefined; +} +``` + +## Troubleshooting + +### No data + +First check your logs for the message `Reading msgraph users and groups`. +If you don't see this, check you've registered the provider, and that the schedule is valid + +If you see a log entry `Read 0 msgraph users and 0 msgraph groups`, check your search and filter arguments. + +If you see the start message (`Reading msgraph users and groups`) but no end message (`Read X msgraph users and Y msgraph groups`), then it is likely the job is taking a long time due to a large volume of data. +The default behavior is to import all users and groups, which is often more data than needed. +Try importing a smaller set of data (e.g. `filter: displayName eq 'John Smith'`). + +### Authentication / Token Errors + +See [Troubleshooting Azure Identity Authentication Issues](https://aka.ms/azsdk/js/identity/troubleshoot) + +### Error while reading users from Microsoft Graph: Authorization_RequestDenied - Insufficient privileges to complete the operation + +- Make sure you've granted all the required permissions to your application registration or managed identity +- Make sure the permissions are `Application` permissions rather than `Delegated` +- If your organization has configured "Admin consent" to be required, make sure this has been granted for your application permissions +- If your group queries are returning Microsoft Teams groups, you may need to grant addition permissions (e.g. `Team.ReadBasic.All`, `TeamMember.Read.All`) +- If you've added additional `select` or `expand` fields, those may need additional permissions granted diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 38c2e7618a..89abd4813b 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -6,6 +6,10 @@ sidebar_label: Org Data description: Importing users and groups from Microsoft Entra ID into Backstage --- +:::info +This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./org--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + The Backstage catalog can be set up to ingest organizational data - users and teams - directly from a tenant in Microsoft Entra ID via the Microsoft Graph API. @@ -39,29 +43,17 @@ catalog: timeout: PT50M ``` -Finally, register the plugin in `catalog.ts`. +:::note For large organizations, this plugin can take a long time, so be careful setting low frequency / timeouts and importing a large amount of users / groups for the first try. +::: -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-next-line */ -import { MicrosoftGraphOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-msgraph'; +Finally, updated your backend by adding the following line: -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - - /* highlight-add-start */ - builder.addEntityProvider( - MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { - logger: env.logger, - scheduler: env.scheduler, - }), - ); - /* highlight-add-end */ - - // .. -} +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-catalog-backend-module-msgraph/alpha')); +/* highlight-add-end */ ``` ## Authenticating with Microsoft Graph @@ -146,27 +138,24 @@ microsoftGraphOrg: search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' ``` +### User photos + +By default, the photos of users will be fetched and added to each user entity. For huge organizations this may be unfeasible, as it will take a _very_ long time, and can be disabled by setting `loadPhotos` to `false`: + +```yaml +microsoftGraphOrg: + providerId: + user: + filter: ... + loadPhotos: false +``` + ## Customizing Transformation Ingested entities can be customized by providing custom transformers. These can be used to completely replace the built in logic, or used to tweak it by using the default transformers (`defaultGroupTransformer`, `defaultUserTransformer` and `defaultOrganizationTransformer` Entities can also be excluded from backstage by returning `undefined`. -These Transformers are be registered when configuring `MicrosoftGraphOrgEntityProvider` - -```ts -builder.addEntityProvider( - MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { - // ... - /* highlight-add-start */ - groupTransformer: myGroupTransformer, - userTransformer: myUserTransformer, - organizationTransformer: myOrganizationTransformer, - /* highlight-add-end */ - }), -); -``` - When using custom transformers, you may want to customize the data returned. Several configuration options can be provided to tweak the Microsoft Graph query to get the data you need @@ -180,9 +169,53 @@ microsoftGraphOrg: select: ['id', 'displayName', 'description'] ``` -The following provides an example of each kind of transformer +### Using Custom Transformers -```ts +Transformers can be configured by extending `microsoftGraphOrgEntityProviderTransformExtensionPoint`. Here is an example: + +```ts title="packages/backend/src/index.ts" +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { microsoftGraphOrgEntityProviderTransformExtensionPoint } from '@backstage/plugin-catalog-backend-module-msgraph/alpha'; +import { + myUserTransformer, + myGroupTransformer, + myOrganizationTransformer, +} from './transformers'; + +backend.add( + createBackendModule({ + pluginId: 'catalog', + moduleId: 'microsoft-graph-extensions', + register(env) { + env.registerInit({ + deps: { + /* highlight-add-start */ + microsoftGraphTransformers: + microsoftGraphOrgEntityProviderTransformExtensionPoint, + /* highlight-add-end */ + }, + async init({ microsoftGraphTransformers }) { + /* highlight-add-start */ + microsoftGraphTransformers.setUserTransformer(myUserTransformer); + microsoftGraphTransformers.setGroupTransformer(myGroupTransformer); + microsoftGraphTransformers.setOrganizationTransformer( + myOrganizationTransformer, + ); + /* highlight-add-end */ + }, + }); + }, + }), +); +``` + +The `myUserTransformer`, `myGroupTransformer`, and `myOrganizationTransformer` transformer functions are from the examples in the section below. + +### Transformer Examples + +The following provides an example of each kind of transformer. We recommend creating a `transformers.ts` file in your `packages/backend/src` folder for these. + +```ts title="packages/backend/src/transformers.ts" import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { defaultGroupTransformer, diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md index 81770afbf8..160827cb0a 100644 --- a/docs/integrations/bitbucketCloud/discovery.md +++ b/docs/integrations/bitbucketCloud/discovery.md @@ -27,7 +27,7 @@ yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-bitbuck ### Installation with New Backend System ```ts -// optional if you want HTTP endpojnts to receive external events +// optional if you want HTTP endpoints to receive external events // backend.add(import('@backstage/plugin-events-backend/alpha')); // optional if you want to use AWS SQS instead of HTTP endpoints to receive external events // backend.add(import('@backstage/plugin-events-backend-module-aws-sqs/alpha')); diff --git a/docs/integrations/bitbucketCloud/locations.md b/docs/integrations/bitbucketCloud/locations.md index e7666efb54..9b08a79c63 100644 --- a/docs/integrations/bitbucketCloud/locations.md +++ b/docs/integrations/bitbucketCloud/locations.md @@ -22,10 +22,18 @@ integrations: appPassword: ${BITBUCKET_CLOUD_PASSWORD} ``` -> Note: A public Bitbucket Cloud provider is added automatically at startup for -> convenience, so you only need to list it if you want to supply credentials. +:::note Note -> Note: The credential used for this is type [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/). An Atlassian Account API key will not work +A public Bitbucket Cloud provider is added automatically at startup for +convenience, so you only need to list it if you want to supply credentials. + +::: + +:::note Note + +The credential used for this is type [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/). An Atlassian Account API key will not work. + +::: Directly under the `bitbucketCloud` key is a list of provider configurations, where you can list the Bitbucket Cloud providers you want to fetch data from. diff --git a/docs/integrations/datadog-rum/installation.md b/docs/integrations/datadog-rum/installation.md index 32eb2b3de8..4dc6c24134 100644 --- a/docs/integrations/datadog-rum/installation.md +++ b/docs/integrations/datadog-rum/installation.md @@ -22,6 +22,8 @@ app: applicationId: qwerty # site: datadoghq.eu # env: 'staging' + # sessionSampleRate: 100 + # sessionReplaySampleRate: 0 ``` If your [`app-config.yaml`](https://github.com/backstage/backstage/blob/e0506af8fc54074a160fb91c83d6cae8172d3bb3/app-config.yaml#L5) file does not have this configuration, you may have to adjust your [`packages/app/public/index.html`](https://github.com/backstage/backstage/blob/e0506af8fc54074a160fb91c83d6cae8172d3bb3/packages/app/public/index.html#L69) to include the Datadog RUM `init()` section manually. diff --git a/docs/integrations/github/discovery--old.md b/docs/integrations/github/discovery--old.md new file mode 100644 index 0000000000..b94cb256c4 --- /dev/null +++ b/docs/integrations/github/discovery--old.md @@ -0,0 +1,376 @@ +--- +id: discovery--old +title: GitHub Discovery +sidebar_label: Discovery +# prettier-ignore +description: Automatically discovering catalog entities from repositories in a GitHub organization +--- + +:::info +This documentation is written for the old backend which has been replaced by [the new backend system](../../backend-system/index.md), being the default since Backstage [version 1.24](../../releases/v1.24.0.md). If have migrated to the new backend system, you may want to read [its own article](./discovery.md) instead. Otherwise, [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + +## GitHub Provider + +The GitHub integration has a discovery provider for discovering catalog +entities within a GitHub organization. The provider will crawl the GitHub +organization and register entities matching the configured path. This can be +useful as an alternative to static locations or manually adding things to the +catalog. This is the preferred method for ingesting entities into the catalog. + +## Installation without Events Support + +You will have to add the provider in the catalog initialization code of your +backend. They are not installed by default, therefore you have to add a +dependency on `@backstage/plugin-catalog-backend-module-github` to your backend +package. + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github +``` + +And then add the entity provider to your catalog builder: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { GithubEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + /* highlight-add-start */ + builder.addEntityProvider( + GithubEntityProvider.fromConfig(env.config, { + logger: env.logger, + scheduler: env.scheduler, + }), + ); + /* highlight-add-end */ + + // .. +} +``` + +## Installation with Events Support + +_For the legacy backend system, please read the sub-section below._ + +The catalog module for GitHub comes with events support enabled. +This will make it subscribe to its relevant topics (`github.push`) +and expects these events to be published via the `EventsService`. + +Additionally, you should install the +[event router by `events-backend-module-github`](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md) +which will route received events from the generic topic `github` to more specific ones +based on the event type (e.g., `github.push`). + +In order to receive Webhook events by GitHub, you have to decide how you want them +to be ingested into Backstage and published to its `EventsService`. +You can decide between the following options (extensible): + +- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) +- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) + +### Legacy Backend System + +Please follow the installation instructions at + +- +- + +Additionally, you need to decide how you want to receive events from external sources like + +- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) +- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) + +Set up your provider + +```ts title="packages/backend/src/plugins/catalog.ts" +import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; +/* highlight-add-next-line */ +import { GithubEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; +import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend'; +import { Router } from 'express'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + builder.addProcessor(new ScaffolderEntitiesProcessor()); + /* highlight-add-start */ + const githubProvider = GithubEntityProvider.fromConfig(env.config, { + events: env.events, + logger: env.logger, + scheduler: env.scheduler, + }); + builder.addEntityProvider(githubProvider); + /* highlight-add-end */ + const { processingEngine, router } = await builder.build(); + await processingEngine.start(); + return router; +} +``` + +You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). The webhook will need to be configured to forward `push` events. + +## Configuration + +To use the discovery provider, you'll need a GitHub integration +[set up](locations.md) with either a [Personal Access Token](../../getting-started/config/authentication.md) or [GitHub Apps](./github-apps.md). For Personal Access Tokens you should pay attention to the [required scopes](https://backstage.io/docs/integrations/github/locations/#token-scopes), where you will need at least the `repo` scope for reading components. For GitHub Apps you will need to grant it the [required permissions](https://backstage.io/docs/integrations/github/github-apps#app-permissions) instead, where you will need at least the `Contents: Read-only` permissions for reading components. + +Then you can add a `github` config to the catalog providers configuration: + +```yaml +catalog: + providers: + github: + # the provider ID can be any camelCase string + providerId: + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string + filters: + branch: 'main' # string + repository: '.*' # Regex + schedule: # same options as in TaskScheduleDefinition + # supports cron, ISO duration, "human duration" as used in code + frequency: { minutes: 30 } + # supports ISO duration, "human duration" as used in code + timeout: { minutes: 3 } + customProviderId: + organization: 'new-org' # string + catalogPath: '/custom/path/catalog-info.yaml' # string + filters: # optional filters + branch: 'develop' # optional string + repository: '.*' # optional Regex + wildcardProviderId: + organization: 'new-org' # string + catalogPath: '/groups/**/*.yaml' # this will search all folders for files that end in .yaml + filters: # optional filters + branch: 'develop' # optional string + repository: '.*' # optional Regex + topicProviderId: + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string + filters: + branch: 'main' # string + repository: '.*' # Regex + topic: 'backstage-exclude' # optional string + topicFilterProviderId: + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string + filters: + branch: 'main' # string + repository: '.*' # Regex + topic: + include: ['backstage-include'] # optional array of strings + exclude: ['experiments'] # optional array of strings + validateLocationsExist: + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string + filters: + branch: 'main' # string + repository: '.*' # Regex + validateLocationsExist: true # optional boolean + visibilityProviderId: + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string + filters: + visibility: + - public + - internal + enterpriseProviderId: + host: ghe.example.net + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string +``` + +This provider supports multiple organizations via unique provider IDs. + +> **Note:** It is possible but certainly not recommended to skip the provider ID level. +> If you do so, `default` will be used as provider ID. + +- **`catalogPath`** _(optional)_: + Default: `/catalog-info.yaml`. + Path where to look for `catalog-info.yaml` files. + You can use wildcards - `*` or `**` - to search the path and/or the filename. + Wildcards cannot be used if the `validateLocationsExist` option is set to `true`. +- **`filters`** _(optional)_: + - **`branch`** _(optional)_: + String used to filter results based on the branch name. + - **`repository`** _(optional)_: + Regular expression used to filter results based on the repository name. + - **`topic`** _(optional)_: + Both of the filters below may be used at the same time but the exclusion filter has the highest priority. + In the example above, a repository with the `backstage-include` topic would still be excluded + if it were also carrying the `experiments` topic. + - **`include`** _(optional)_: + An array of strings used to filter in results based on their associated GitHub topics. + If configured, only repositories with one (or more) topic(s) present in the inclusion filter will be ingested + - **`exclude`** _(optional)_: + An array of strings used to filter out results based on their associated GitHub topics. + If configured, all repositories _except_ those with one (or more) topics(s) present in the exclusion filter will be ingested. + - **`visibility`** _(optional)_: + An array of strings used to filter results based on their visibility. Available options are `private`, `internal`, `public`. If configured (non empty), only repositories with visibility present in the filter will be ingested +- **`host`** _(optional)_: + The hostname of your GitHub Enterprise instance. It must match a host defined in [integrations.github](locations.md). +- **`organization`**: + Name of your organization account/workspace. + If you want to add multiple organizations, you need to add one provider config each. +- **`validateLocationsExist`** _(optional)_: + Whether to validate locations that exist before emitting them. + This option avoids generating locations for catalog info files that do not exist in the source repository. + Defaults to `false`. + Due to limitations in the GitHub API's ability to query for repository objects, this option cannot be used in + conjunction with wildcards in the `catalogPath`. +- **`schedule`**: + - **`frequency`**: + How often you want the task to run. The system does its best to avoid overlapping invocations. + - **`timeout`**: + The maximum amount of time that a single task invocation can take. + - **`initialDelay`** _(optional)_: + The amount of time that should pass before the first invocation happens. + - **`scope`** _(optional)_: + `'global'` or `'local'`. Sets the scope of concurrency control. + +## GitHub API Rate Limits + +GitHub [rate limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) API requests to 5,000 per hour (or more for Enterprise +accounts). The snippet below refreshes the Backstage catalog data every 35 minutes, which issues an API request for each discovered location. + +If your requests are too frequent then you may get throttled by +rate limiting. You can change the refresh frequency of the catalog in your `app-config.yaml` file by controlling the `schedule`. + +```yaml +schedule: + frequency: { minutes: 35 } + timeout: { minutes: 3 } +``` + +More information about scheduling can be found on the [TaskScheduleDefinition](https://backstage.io/docs/reference/backend-tasks.taskscheduledefinition) page. + +Alternatively, or additionally, you can configure [github-apps](github-apps.md) authentication +which carries a much higher rate limit at GitHub. + +This is true for any method of adding GitHub entities to the catalog, but +especially easy to hit with automatic discovery. + +## GitHub Processor (To Be Deprecated) + +The GitHub integration has a special discovery processor for discovering catalog +entities within a GitHub organization. The processor will crawl the GitHub +organization and register entities matching the configured path. This can be +useful as an alternative to static locations or manually adding things to the +catalog. + +## Installation + +You will have to add the processors in the catalog initialization code of your +backend. They are not installed by default, therefore you have to add a +dependency on `@backstage/plugin-catalog-backend-module-github` to your backend +package, plus `@backstage/integration` for the basic credentials management: + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/integration @backstage/plugin-catalog-backend-module-github +``` + +And then add the processors to your catalog builder: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-start */ +import { + GithubDiscoveryProcessor, + GithubOrgReaderProcessor, +} from '@backstage/plugin-catalog-backend-module-github'; +import { + ScmIntegrations, + DefaultGithubCredentialsProvider, +} from '@backstage/integration'; +/* highlight-add-end */ + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + /* highlight-add-start */ + const integrations = ScmIntegrations.fromConfig(env.config); + const githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + builder.addProcessor( + GithubDiscoveryProcessor.fromConfig(env.config, { + logger: env.logger, + githubCredentialsProvider, + }), + GithubOrgReaderProcessor.fromConfig(env.config, { + logger: env.logger, + githubCredentialsProvider, + }), + ); + /* highlight-add-end */ + + // .. +} +``` + +## Configuration + +To use the discovery processor, you'll need a GitHub integration +[set up](locations.md) with either a [Personal Access Token](../../getting-started/config/authentication.md) or [GitHub Apps](./github-apps.md). + +Then you can add a location target to the catalog configuration: + +```yaml +catalog: + locations: + # (since 0.13.5) Scan all repositories for a catalog-info.yaml in the root of the default branch + - type: github-discovery + target: https://github.com/myorg + # Or use a custom pattern for a subset of all repositories with default repository + - type: github-discovery + target: https://github.com/myorg/service-*/blob/-/catalog-info.yaml + # Or use a custom file format and location + - type: github-discovery + target: https://github.com/*/blob/-/docs/your-own-format.yaml + # Or use a specific branch-name + - type: github-discovery + target: https://github.com/*/blob/backstage-docs/catalog-info.yaml +``` + +Note the `github-discovery` type, as this is not a regular `url` processor. + +When using a custom pattern, the target is composed of three parts: + +- The base organization URL, `https://github.com/myorg` in this case +- The repository blob to scan, which accepts \* wildcard tokens. This can simply + be `*` to scan all repositories in the organization. This example only looks + for repositories prefixed with `service-`. +- The path within each repository to find the catalog YAML file. This will + usually be `/blob/main/catalog-info.yaml`, `/blob/master/catalog-info.yaml` or + a similar variation for catalog files stored in the root directory of each + repository. You could also use a dash (`-`) for referring to the default + branch. + +## GitHub API Rate Limits + +GitHub [rate limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) API requests to 5,000 per hour (or more for Enterprise +accounts). The default Backstage catalog backend refreshes data every 100 +seconds, which issues an API request for each discovered location. + +This means if you have more than ~140 catalog entities, you may get throttled by +rate limiting. You can change the refresh rate of the catalog in your `packages/backend/src/plugins/catalog.ts` file: + +```typescript +const builder = await CatalogBuilder.create(env); + +// For example, to refresh every 5 minutes (300 seconds). +builder.setProcessingIntervalSeconds(300); +``` + +Alternatively, or additionally, you can configure [github-apps](github-apps.md) authentication +which carries a much higher rate limit at GitHub. + +This is true for any method of adding GitHub entities to the catalog, but +especially easy to hit with automatic discovery. diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index d0721e06f6..920cea9297 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -6,6 +6,10 @@ sidebar_label: Discovery description: Automatically discovering catalog entities from repositories in a GitHub organization --- +:::info +This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./discovery--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + ## GitHub Provider The GitHub integration has a discovery provider for discovering catalog @@ -14,10 +18,9 @@ organization and register entities matching the configured path. This can be useful as an alternative to static locations or manually adding things to the catalog. This is the preferred method for ingesting entities into the catalog. -## Installation without Events Support +## Installation -You will have to add the provider in the catalog initialization code of your -backend. They are not installed by default, therefore you have to add a +You will have to add the GitHub Entity provider to your backend as it is not installed by default, therefore you have to add a dependency on `@backstage/plugin-catalog-backend-module-github` to your backend package. @@ -29,13 +32,12 @@ yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github And then update your backend by adding the following line: ```ts title="packages/backend/src/index.ts" -// github discovery +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +/* highlight-add-start */ backend.add(import('@backstage/plugin-catalog-backend-module-github/alpha')); ``` -## Installation with Events Support - -_For the legacy backend system, please read the sub-section below._ +## Events Support The catalog module for GitHub comes with events support enabled. This will make it subscribe to its relevant topics (`github.push`) @@ -53,47 +55,6 @@ You can decide between the following options (extensible): - [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) - [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) -### Legacy Backend System - -Please follow the installation instructions at - -- -- - -Additionally, you need to decide how you want to receive events from external sources like - -- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) -- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) - -Set up your provider - -```ts title="packages/backend/src/plugins/catalog.ts" -import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; -/* highlight-add-next-line */ -import { GithubEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; -import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend'; -import { Router } from 'express'; -import { PluginEnvironment } from '../types'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - builder.addProcessor(new ScaffolderEntitiesProcessor()); - /* highlight-add-start */ - const githubProvider = GithubEntityProvider.fromConfig(env.config, { - events: env.events, - logger: env.logger, - scheduler: env.scheduler, - }); - builder.addEntityProvider(githubProvider); - /* highlight-add-end */ - const { processingEngine, router } = await builder.build(); - await processingEngine.start(); - return router; -} -``` - You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). The webhook will need to be configured to forward `push` events. ## Configuration @@ -169,8 +130,12 @@ catalog: This provider supports multiple organizations via unique provider IDs. -> **Note:** It is possible but certainly not recommended to skip the provider ID level. -> If you do so, `default` will be used as provider ID. +:::note Note + +It is possible but certainly not recommended to skip the provider ID level. +If you do so, `default` will be used as provider ID. + +::: - **`catalogPath`** _(optional)_: Default: `/catalog-info.yaml`. @@ -236,121 +201,3 @@ which carries a much higher rate limit at GitHub. This is true for any method of adding GitHub entities to the catalog, but especially easy to hit with automatic discovery. - -## GitHub Processor (To Be Deprecated) - -The GitHub integration has a special discovery processor for discovering catalog -entities within a GitHub organization. The processor will crawl the GitHub -organization and register entities matching the configured path. This can be -useful as an alternative to static locations or manually adding things to the -catalog. - -## Installation - -You will have to add the processors in the catalog initialization code of your -backend. They are not installed by default, therefore you have to add a -dependency on `@backstage/plugin-catalog-backend-module-github` to your backend -package, plus `@backstage/integration` for the basic credentials management: - -```bash -# From your Backstage root directory -yarn --cwd packages/backend add @backstage/integration @backstage/plugin-catalog-backend-module-github -``` - -And then add the processors to your catalog builder: - -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-start */ -import { - GithubDiscoveryProcessor, - GithubOrgReaderProcessor, -} from '@backstage/plugin-catalog-backend-module-github'; -import { - ScmIntegrations, - DefaultGithubCredentialsProvider, -} from '@backstage/integration'; -/* highlight-add-end */ - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - /* highlight-add-start */ - const integrations = ScmIntegrations.fromConfig(env.config); - const githubCredentialsProvider = - DefaultGithubCredentialsProvider.fromIntegrations(integrations); - builder.addProcessor( - GithubDiscoveryProcessor.fromConfig(env.config, { - logger: env.logger, - githubCredentialsProvider, - }), - GithubOrgReaderProcessor.fromConfig(env.config, { - logger: env.logger, - githubCredentialsProvider, - }), - ); - /* highlight-add-end */ - - // .. -} -``` - -## Configuration - -To use the discovery processor, you'll need a GitHub integration -[set up](locations.md) with either a [Personal Access Token](../../getting-started/config/authentication.md) or [GitHub Apps](./github-apps.md). - -Then you can add a location target to the catalog configuration: - -```yaml -catalog: - locations: - # (since 0.13.5) Scan all repositories for a catalog-info.yaml in the root of the default branch - - type: github-discovery - target: https://github.com/myorg - # Or use a custom pattern for a subset of all repositories with default repository - - type: github-discovery - target: https://github.com/myorg/service-*/blob/-/catalog-info.yaml - # Or use a custom file format and location - - type: github-discovery - target: https://github.com/*/blob/-/docs/your-own-format.yaml - # Or use a specific branch-name - - type: github-discovery - target: https://github.com/*/blob/backstage-docs/catalog-info.yaml -``` - -Note the `github-discovery` type, as this is not a regular `url` processor. - -When using a custom pattern, the target is composed of three parts: - -- The base organization URL, `https://github.com/myorg` in this case -- The repository blob to scan, which accepts \* wildcard tokens. This can simply - be `*` to scan all repositories in the organization. This example only looks - for repositories prefixed with `service-`. -- The path within each repository to find the catalog YAML file. This will - usually be `/blob/main/catalog-info.yaml`, `/blob/master/catalog-info.yaml` or - a similar variation for catalog files stored in the root directory of each - repository. You could also use a dash (`-`) for referring to the default - branch. - -## GitHub API Rate Limits - -GitHub [rate limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) API requests to 5,000 per hour (or more for Enterprise -accounts). The default Backstage catalog backend refreshes data every 100 -seconds, which issues an API request for each discovered location. - -This means if you have more than ~140 catalog entities, you may get throttled by -rate limiting. You can change the refresh rate of the catalog in your `packages/backend/src/plugins/catalog.ts` file: - -```typescript -const builder = await CatalogBuilder.create(env); - -// For example, to refresh every 5 minutes (300 seconds). -builder.setProcessingIntervalSeconds(300); -``` - -Alternatively, or additionally, you can configure [github-apps](github-apps.md) authentication -which carries a much higher rate limit at GitHub. - -This is true for any method of adding GitHub entities to the catalog, but -especially easy to hit with automatic discovery. diff --git a/docs/integrations/github/github-apps.md b/docs/integrations/github/github-apps.md index 96363bc719..b5e252be74 100644 --- a/docs/integrations/github/github-apps.md +++ b/docs/integrations/github/github-apps.md @@ -31,7 +31,7 @@ A GitHub app created with the cli will have read access by default. You have to manually update the GitHub App settings in GitHub to grant the app more permissions if needed. -### Using the CLI (public GitHub only) +## Using the CLI (public GitHub only) You can use the `backstage-cli` to create a GitHub App using a manifest file that we provide. This gives us a way to automate some of the work required to @@ -42,7 +42,7 @@ yarn backstage-cli create-github-app ``` You can read more about the -[`backstage-cli create-github-app`](../../local-dev/cli-commands.md#create-github-app) command. +[`backstage-cli create-github-app`](../../tooling/cli/03-commands.md#create-github-app) command. Once you've gone through the CLI command, it should produce a YAML file in the root of the project which you can then use as an `include` in your @@ -53,7 +53,7 @@ Note that the created app will have a webhook that is disabled by default and points to `smee.io`, which is intended for local development. There's also currently no part of Backstage that makes use of the webhook. -### GitHub Enterprise +## GitHub Enterprise You have to create the GitHub Application manually using these [instructions](https://docs.github.com/en/free-pro-team@latest/developers/apps/creating-a-github-app) @@ -76,7 +76,7 @@ privateKey: | -----END RSA PRIVATE KEY----- ``` -### Including in Integrations Config +## Including in Integrations Config Once the credentials are stored in a YAML file generated by `create-github-app`, or manually by following the [GitHub Enterprise](#github-enterprise) @@ -95,7 +95,25 @@ integrations: - $include: example-backstage-app-credentials.yaml ``` -### Limiting the GitHub App installations +Alternatively you can use environment variables as well: + +```yaml +integrations: + github: + - host: github.com + apps: + - appId: ${AUTH_ORG_APP_ID} + clientId: ${AUTH_ORG_CLIENT_ID} + clientSecret: ${AUTH_ORG_CLIENT_SECRET} + privateKey: ${AUTH_ORG1_PRIVATE_KEY} + webhookSecret: ${AUTH_ORG_WEBHOOK_SECRET} +``` + +:::Note +Note that in both examples above `apps` is an array which means you can add multiple GitHub Apps using `$include` or environment variables as long as they are each for a different GitHub Org as mentioned under the [Caveats](#caveats) section +::: + +## Limiting the GitHub App installations If you want to limit the GitHub app installations visible to backstage you may optionally include the `allowedInstallationOwners` option. If you configure @@ -117,7 +135,7 @@ privateKey: | This will result in backstage preventing the use of any installation that is not within the allow list. -### App permissions +## App permissions When creating a GitHub App, you must select permissions to define the level of access for the app. The permissions required vary depending on your use of the @@ -125,6 +143,7 @@ integration: - Reading software components: - `Contents`: `Read-only` + - `Commit statuses`: `Read-only` - Reading organization data: - `Members`: `Read-only` - Publishing software templates: @@ -135,12 +154,24 @@ integration: - `Pull requests`: `Read & write` - `Issues`: `Read & write` - `Workflows`: `Read & write` (if templates include GitHub workflows) - - `Commit statuses`: `Read-only` - `Variables`: `Read & write` (if templates include GitHub Action Repository Variables) - `Secrets`: `Read & write` (if templates include GitHub Action Repository Secrets) - `Environments`: `Read & write` (if templates include GitHub Environments) -### Troubleshooting +## Updating Permissions + +There may be times where you need to update the permissions for your GitHub App, to easily get at the GitHub App you can find it at this URL: + +```sh +https://github.com/organizations/{ORG}/settings/apps/{APP_NAME}/permissions +``` + +**Please note that when you change permissions, the app owner will get an email +that must be approved first before the changes are applied.** + +![email](../../assets/integrations/github/email.png) + +## Troubleshooting `HttpError: This endpoint requires you to be authenticated.` diff --git a/docs/integrations/github/locations.md b/docs/integrations/github/locations.md index 7d3ce632d6..ae83b38e1e 100644 --- a/docs/integrations/github/locations.md +++ b/docs/integrations/github/locations.md @@ -28,9 +28,11 @@ integrations: token: ${GHE_TOKEN} ``` -> Note: A public GitHub provider is added automatically at startup for -> convenience, so you only need to list it if you want to supply a -> [token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). +:::note Note + +A public GitHub provider is added automatically at startup for convenience, so you only need to list it if you want to supply a [token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). + +::: Directly under the `github` key is a list of provider configurations, where you can list the various GitHub-compatible providers you want to be able to fetch diff --git a/docs/integrations/github/org--old.md b/docs/integrations/github/org--old.md new file mode 100644 index 0000000000..3d1639a924 --- /dev/null +++ b/docs/integrations/github/org--old.md @@ -0,0 +1,367 @@ +--- +id: org--old +title: GitHub Organizational Data +sidebar_label: Org Data +# prettier-ignore +description: Importing users and groups from a GitHub organization into Backstage +--- + +:::info +This documentation is written for the old backend which has been replaced by [the new backend system](../../backend-system/index.md), being the default since Backstage [version 1.24](../../releases/v1.24.0.md). If have migrated to the new backend system, you may want to read [its own article](./org.md) instead.Otherwise, [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + +The Backstage catalog can be set up to ingest organizational data - users and +teams - directly from an organization in GitHub or GitHub Enterprise. The result +is a hierarchy of +[`User`](../../features/software-catalog/descriptor-format.md#kind-user) and +[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind +entities that mirror your org setup. + +> Note: This adds `User` and `Group` entities to the catalog, but does not +> provide authentication. See the +> [GitHub auth provider](../../auth/github/provider.md) for that. + +## Installation without Events Support + +This guide will use the Entity Provider method. If you for some reason prefer +the Processor method (not recommended), it is described separately below. + +The provider is not installed by default, therefore you have to add a dependency +to `@backstage/plugin-catalog-backend-module-github` to your backend package. + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github +``` + +> Note: When configuring to use a Provider instead of a Processor you do not +> need to add a _location_ pointing to your GitHub server/organization + +Update the catalog plugin initialization in your backend to add the provider and +schedule it: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + /* highlight-add-start */ + // The org URL below needs to match a configured integrations.github entry + // specified in your app-config. + builder.addEntityProvider( + GithubOrgEntityProvider.fromConfig(env.config, { + id: 'production', + orgUrl: 'https://github.com/backstage', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }), + ); + /* highlight-add-end */ + + // .. +} +``` + +Alternatively, if you wish to ingest data from multiple GitHub organizations you can use +the `GithubMultiOrgEntityProvider` instead. Note that by default, this provider will namespace +groups according to the org they originate from to avoid potential name duplicates: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { GithubMultiOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + /* highlight-add-start */ + // The GitHub URL below needs to match a configured integrations.github entry + // specified in your app-config. + builder.addEntityProvider( + GithubMultiOrgEntityProvider.fromConfig(env.config, { + id: 'production', + githubUrl: 'https://github.com', + // Set the following to list the GitHub orgs you wish to ingest from. You can + // also omit this option to ingest all orgs accessible by your GitHub integration + orgs: ['org-a', 'org-b'], + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }), + ); + /* highlight-add-end */ + + // .. +} +``` + +## Installation with Events Support + +_For the legacy backend system, please read the subsection below._ + +The catalog module `github-org` comes with events support enabled for the `GithubMultiOrgEntityProvider`. +This will make it subscribe to its relevant topics and expects these events to be published via the `EventsService`. + +Topics: + +- `github.installation` +- `github.membership` +- `github.organization` +- `github.team` + +Additionally, you should install the +[event router by `events-backend-module-github`](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md) +which will route received events from the generic topic `github` to more specific ones +based on the event type (e.g., `github.membership`). + +In order to receive Webhook events by GitHub, you have to decide how you want them +to be ingested into Backstage and published to its `EventsService`. +You can decide between the following options (extensible): + +- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) +- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) + +### Legacy Backend System + +Please follow the installation instructions at + +- +- + +Additionally, you need to decide how you want to receive events from external sources like + +- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) +- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) + +Set up your provider + +```ts title="packages/backend/src/plugins/catalog.ts" +import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; +/* highlight-add-next-line */ +import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; +import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend'; +import { Router } from 'express'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + builder.addProcessor(new ScaffolderEntitiesProcessor()); + /* highlight-add-start */ + const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, { + id: 'production', + orgUrl: 'https://github.com/backstage', + logger: env.logger, + events: env.events, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }); + builder.addEntityProvider(githubOrgProvider); + /* highlight-add-end */ + const { processingEngine, router } = await builder.build(); + await processingEngine.start(); + return router; +} +``` + +Or, alternatively, if using the `GithubMultiOrgEntityProvider`: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { GithubMultiOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + /* highlight-add-start */ + // The GitHub URL below needs to match a configured integrations.github entry + // specified in your app-config. + builder.addEntityProvider( + GithubMultiOrgEntityProvider.fromConfig(env.config, { + id: 'production', + githubUrl: 'https://github.com', + // Set the following to list the GitHub orgs you wish to ingest from. You can + // also omit this option to ingest all orgs accessible by your GitHub integration + orgs: ['org-a', 'org-b'], + logger: env.logger, + events: env.events, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }), + ); + /* highlight-add-end */ + + // .. +} +``` + +You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). +The webhook will need to be configured to forward `organization`,`team` and `membership` events. + +## Configuration + +As mentioned above, you also must have some configuration in your app-config +that describes the targets that you want to import. This lets the entity +provider know what authorization to use, and what the API endpoints are. You may +or may not have such an entry already added since before: + +```yaml +integrations: + github: + # example for public github + - host: github.com + token: ${GITHUB_TOKEN} + # example for a private GitHub Enterprise instance + - host: ghe.example.net + apiBaseUrl: https://ghe.example.net/api/v3 + token: ${GHE_TOKEN} +``` + +These examples use `${}` placeholders to reference environment variables. This +is often suitable for production setups, but also means that you will have to +supply those variables to the backend as it starts up. If you want, for local +development in particular, you can experiment first by putting the actual tokens +in a mirrored config directly in your `app-config.local.yaml` as well. + +If Backstage is configured to use GitHub Apps authentication you must grant +`Read-Only` access for `Members` under `Organization` in order to ingest users +correctly. You can modify the app's permissions under the organization settings, +`https://github.com/organizations/{ORG}/settings/apps/{APP_NAME}/permissions`. + +![permissions](../../assets/integrations/github/permissions.png) + +**Please note that when you change permissions, the app owner will get an email +that must be approved first before the changes are applied.** + +![email](../../assets/integrations/github/email.png) + +### Custom Transformers + +You can inject your own transformation logic to help map from GH API responses +into backstage entities. You can do this on the user and team requests to +enable you to do further processing or updates to the entities. + +To enable this you pass a function into the `GitHubOrgEntityProvider`. You can +pass a `UserTransformer`, `TeamTransformer` or both. The function is invoked +for each item (user or team) that is returned from the API. You can either +return an Entity (User or Group) or `undefined` if you do not want to import +that item. + +There is also a `defaultUserTransformer` and `defaultOrganizationTeamTransformer`. +You could use these and simply decorate the response from the default +transformation if you only need to change a few properties. + +### Resolving GitHub users via organization email + +When you authenticate users you should resolve them to an entity within the +catalog. Often the authentication you use could be a corporate SSO system that +provides you with email as a key. To enable you to find and resolve GitHub users +it's useful to also import the private domain verified emails into the User +entity in backstage. + +The integration attempts to return `organizationVerifiedDomainEmails` from the +GitHub API and makes this available as part of the object passed to +`UserTransformer`. The GitHub API will only return emails that use a domain +that's a verified domain for your GitHub Org. It also relies on the user having +configured such an email in their own account. The API will only return these +values when using GitHub App authentication and with the correct app permission +allowing access to emails. + +You can decorate the default `userTransformer` to replace the org email in the +returned identity. + +```ts title="packages/backend/src/plugins/catalog.ts" +const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, { + id: 'production', + orgUrl: 'https://github.com/backstage', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + /* highlight-add-start */ + userTransformer: async (user, ctx) => { + const entity = await defaultUserTransformer(user, ctx); + if (entity && user.organizationVerifiedDomainEmails?.length) { + entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0]; + } + return entity; + }, + /* highlight-add-end */ +}); +``` + +Once you have imported the emails you can resolve users in your [sign-in resolver](../../auth/github/provider.md) using the catalog entity search via email + +```typescript title="packages/backend/src/plugins/auth.ts" +ctx.signInWithCatalogUser({ + filter: { + kind: ['User'], + 'spec.profile.email': email as string, + }, +}); +``` + +## Using a Processor instead of a Provider + +An alternative to using the Provider for ingesting organizational entities is to +use a Processor. This is the old way that's based on registering locations with +the proper type and target, triggering the processor to run. + +The drawback of this method is that it will leave orphaned Group/User entities +whenever they are deleted on your GitHub server, and you cannot control the +frequency with which they are refreshed, separately from other processors. + +### Processor Installation + +The `GithubOrgReaderProcessor` is not registered by default, so you have to +install and register it in the catalog plugin: + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github +``` + +```typescript title="packages/backend/src/plugins/catalog.ts" +import { GithubOrgReaderProcessor } from '@backstage/plugin-catalog-backend-module-github'; + +builder.addProcessor( + GithubOrgReaderProcessor.fromConfig(env.config, { logger: env.logger }), +); +``` + +### Processor Configuration + +The integration section of your app-config needs to be set up in the same way as +for the Entity Provider - see above. + +In addition to that, you typically want to add a few static locations to your +app-config, which reference your organizations to import. The following +configuration enables an import of the teams and users under the org +`https://github.com/my-org-name` on public GitHub. + +```yaml +catalog: + locations: + - type: github-org + target: https://github.com/my-org-name + rules: + - allow: [User, Group] +``` diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index 974362c125..f94ffe6c7a 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -6,6 +6,10 @@ sidebar_label: Org Data description: Importing users and groups from a GitHub organization into Backstage --- +:::info +This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./org--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)! +::: + The Backstage catalog can be set up to ingest organizational data - users and teams - directly from an organization in GitHub or GitHub Enterprise. The result is a hierarchy of @@ -13,99 +17,89 @@ is a hierarchy of [`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind entities that mirror your org setup. -> Note: This adds `User` and `Group` entities to the catalog, but does not -> provide authentication. See the -> [GitHub auth provider](../../auth/github/provider.md) for that. +:::note Note -## Installation without Events Support +This adds `User` and `Group` entities to the catalog, but does not +provide authentication. See the +[GitHub auth provider](../../auth/github/provider.md) for that. -This guide will use the Entity Provider method. If you for some reason prefer -the Processor method (not recommended), it is described separately below. +::: -The provider is not installed by default, therefore you have to add a dependency -to `@backstage/plugin-catalog-backend-module-github` to your backend package. +## Permissions + +Prior to installing the GitHub Org provider you should confirm you have the right permissions: + +- Personal Access Token permissions are listed in the [GitHub Locations](./locations.md#token-scopes) documentation +- GitHub App(s) permissions are listed in the [GitHub Apps](./github-apps.md#app-permissions) documentation + +## Installation + +You will have to add the GitHub Org provider to your backend as it is not installed by default, therefore you have to add a +dependency on `@backstage/plugin-catalog-backend-module-github-org` to your backend +package. ```bash # From your Backstage root directory -yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github-org ``` -> Note: When configuring to use a Provider instead of a Processor you do not -> need to add a _location_ pointing to your GitHub server/organization +Next add the basic configuration to `app-config.yaml` -Update the catalog plugin initialization in your backend to add the provider and -schedule it: - -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-next-line */ -import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - - /* highlight-add-start */ - // The org URL below needs to match a configured integrations.github entry - // specified in your app-config. - builder.addEntityProvider( - GithubOrgEntityProvider.fromConfig(env.config, { - id: 'production', - orgUrl: 'https://github.com/backstage', - logger: env.logger, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 60 }, - timeout: { minutes: 15 }, - }), - }), - ); - /* highlight-add-end */ - - // .. -} +```yaml title="app-config.yaml" +catalog: + providers: + githubOrg: + id: production + githubUrl: https://github.com + orgs: ['organization-1', 'organization-2', 'organization-3'] + schedule: + initialDelay: { seconds: 30 } + frequency: { hours: 1 } + timeout: { minutes: 50 } ``` -Alternatively, if you wish to ingest data from multiple GitHub organizations you can use -the `GithubMultiOrgEntityProvider` instead. Note that by default, this provider will namespace -groups according to the org they originate from to avoid potential name duplicates: +Finally, update your backend by adding the following line: -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-next-line */ -import { GithubMultiOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - - /* highlight-add-start */ - // The GitHub URL below needs to match a configured integrations.github entry - // specified in your app-config. - builder.addEntityProvider( - GithubMultiOrgEntityProvider.fromConfig(env.config, { - id: 'production', - githubUrl: 'https://github.com', - // Set the following to list the GitHub orgs you wish to ingest from. You can - // also omit this option to ingest all orgs accessible by your GitHub integration - orgs: ['org-a', 'org-b'], - logger: env.logger, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 60 }, - timeout: { minutes: 15 }, - }), - }), - ); - /* highlight-add-end */ - - // .. -} +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-catalog-backend-module-github-org')); ``` -## Installation with Events Support +### Configuration Details -_For the legacy backend system, please read the subsection below._ +In the installation steps above we included an simple example of the needed configuration. The section goes into more details about the various configuration options. -The catalog module `github-org` comes with events support enabled for the `GithubMultiOrgEntityProvider`. +```yaml title="app-config.yaml" +catalog: + providers: + githubOrg: + - id: github + githubUrl: https://github.com + orgs: ['organization-1', 'organization-2', 'organization-3'] + schedule: + initialDelay: { seconds: 30 } + frequency: { hours: 1 } + timeout: { minutes: 50 } + - id: ghe + githubUrl: https://ghe.mycompany.com + orgs: ['internal-1', 'internal-2', 'internal-3'] + schedule: + initialDelay: { seconds: 30 } + frequency: { hours: 1 } + timeout: { minutes: 50 } +``` + +Directly under the `githubOrg` is a list of configurations, each entry is a structure with the following elements: + +- `id`: A stable id for this provider. Entities from this provider will be associated with this ID, so you should take care not to change it over time since that may lead to orphaned entities and/or conflicts. +- `githubUrl`: The target that this provider should consume +- `orgs` (optional): The list of the GitHub orgs to consume. If you only list a single org the generated group entities will use the `default` namespace, otherwise they will use the org name as the namespace. By default the provider will consume all accessible orgs on the given GitHub instance (support for GitHub App integration only). +- `schedule`: The refresh schedule to use, matches the structure of [`TaskScheduleDefinitionConfig`](https://backstage.io/docs/reference/backend-tasks.taskscheduledefinitionconfig/) + +### Events Support + +The catalog module for GitHub Org comes with events support enabled. This will make it subscribe to its relevant topics and expects these events to be published via the `EventsService`. Topics: @@ -127,128 +121,10 @@ You can decide between the following options (extensible): - [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) - [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) -### Legacy Backend System - -Please follow the installation instructions at - -- -- - -Additionally, you need to decide how you want to receive events from external sources like - -- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) -- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) - -Set up your provider - -```ts title="packages/backend/src/plugins/catalog.ts" -import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; -/* highlight-add-next-line */ -import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; -import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend'; -import { Router } from 'express'; -import { PluginEnvironment } from '../types'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - builder.addProcessor(new ScaffolderEntitiesProcessor()); - /* highlight-add-start */ - const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, { - id: 'production', - orgUrl: 'https://github.com/backstage', - logger: env.logger, - events: env.events, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 60 }, - timeout: { minutes: 15 }, - }), - }); - builder.addEntityProvider(githubOrgProvider); - /* highlight-add-end */ - const { processingEngine, router } = await builder.build(); - await processingEngine.start(); - return router; -} -``` - -Or, alternatively, if using the `GithubMultiOrgEntityProvider`: - -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-next-line */ -import { GithubMultiOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - - /* highlight-add-start */ - // The GitHub URL below needs to match a configured integrations.github entry - // specified in your app-config. - builder.addEntityProvider( - GithubMultiOrgEntityProvider.fromConfig(env.config, { - id: 'production', - githubUrl: 'https://github.com', - // Set the following to list the GitHub orgs you wish to ingest from. You can - // also omit this option to ingest all orgs accessible by your GitHub integration - orgs: ['org-a', 'org-b'], - logger: env.logger, - events: env.events, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 60 }, - timeout: { minutes: 15 }, - }), - }), - ); - /* highlight-add-end */ - - // .. -} -``` - You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). The webhook will need to be configured to forward `organization`,`team` and `membership` events. -## Configuration - -As mentioned above, you also must have some configuration in your app-config -that describes the targets that you want to import. This lets the entity -provider know what authorization to use, and what the API endpoints are. You may -or may not have such an entry already added since before: - -```yaml -integrations: - github: - # example for public github - - host: github.com - token: ${GITHUB_TOKEN} - # example for a private GitHub Enterprise instance - - host: ghe.example.net - apiBaseUrl: https://ghe.example.net/api/v3 - token: ${GHE_TOKEN} -``` - -These examples use `${}` placeholders to reference environment variables. This -is often suitable for production setups, but also means that you will have to -supply those variables to the backend as it starts up. If you want, for local -development in particular, you can experiment first by putting the actual tokens -in a mirrored config directly in your `app-config.local.yaml` as well. - -If Backstage is configured to use GitHub Apps authentication you must grant -`Read-Only` access for `Members` under `Organization` in order to ingest users -correctly. You can modify the app's permissions under the organization settings, -`https://github.com/organizations/{ORG}/settings/apps/{APP_NAME}/permissions`. - -![permissions](../../assets/integrations/github/permissions.png) - -**Please note that when you change permissions, the app owner will get an email -that must be approved first before the changes are applied.** - -![email](../../assets/integrations/github/email.png) - -### Custom Transformers +## Custom Transformers You can inject your own transformation logic to help map from GH API responses into backstage entities. You can do this on the user and team requests to @@ -264,6 +140,81 @@ There is also a `defaultUserTransformer` and `defaultOrganizationTeamTransformer You could use these and simply decorate the response from the default transformation if you only need to change a few properties. +Here's an example of how to use the transformers: + +```ts title="packages/backend/src/index.ts" +import { createBackend } from '@backstage/backend-defaults'; +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { githubOrgEntityProviderTransformsExtensionPoint } from '@backstage/plugin-catalog-backend-module-github-org'; +import { myTeamTransformer, myUserTransformer } from './transformers'; + +const githubOrgModule = createBackendModule({ + pluginId: 'catalog', + moduleId: 'github-org-extensions', + register(env) { + env.registerInit({ + deps: { + githubOrg: githubOrgEntityProviderTransformsExtensionPoint, + }, + async init({ githubOrg }) { + githubOrg.setTeamTransformer(myTeamTransformer); + githubOrg.setUserTransformer(myUserTransformer); + }, + }); + }, +}); + +const backend = createBackend(); + +// Other items + +backend.add(import('@backstage/plugin-catalog-backend/alpha')); + +backend.add(githubOrgModule()); + +backend.start(); +``` + +The `myTeamTransformer` and `myUserTransformer` transformer functions are from the examples in the section below. + +### Transformer Examples + +The following provides an example of each kind of transformer. We recommend creating a `transformers.ts` file in your `packages/backend/src` folder for these. + +```ts title="packages/backend/src/transformers.ts" +import { + TeamTransformer, + UserTransformer, + defaultUserTransformer, +} from '@backstage/plugin-catalog-backend-module-github'; + +// This team transformer completely replaces the built in logic with custom logic. +export const myTeamTransformer: TeamTransformer = async team => { + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: team.slug, + annotations: {}, + }, + spec: { + type: 'GitHub Org Team', + profile: {}, + children: [], + }, + }; +}; + +// This user transformer makes use of the built in logic, but also sets the description field +export const myUserTransformer: UserTransformer = async (user, ctx) => { + const backstageUser = await defaultUserTransformer(user, ctx); + if (backstageUser) { + backstageUser.metadata.description = 'Loaded from GitHub Org Data'; + } + return backstageUser; +}; +``` + ### Resolving GitHub users via organization email When you authenticate users you should resolve them to an entity within the @@ -283,31 +234,22 @@ allowing access to emails. You can decorate the default `userTransformer` to replace the org email in the returned identity. -```ts title="packages/backend/src/plugins/catalog.ts" -const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, { - id: 'production', - orgUrl: 'https://github.com/backstage', - logger: env.logger, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 60 }, - timeout: { minutes: 15 }, - }), - /* highlight-add-start */ - userTransformer: async (user, ctx) => { - const entity = await defaultUserTransformer(user, ctx); - if (entity && user.organizationVerifiedDomainEmails?.length) { - entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0]; - } - return entity; - }, - /* highlight-add-end */ -}); +```ts title="packages/backend/src/transformers.ts" +export const myVerifiedUserTransformer: UserTransformer = async (user, ctx) => { + const backstageUser = await defaultUserTransformer(user, ctx); + if (backstageUser && user.organizationVerifiedDomainEmails?.length) { + backstageUser.spec.profile!.email = + user.organizationVerifiedDomainEmails[0]; + } + return backstageUser; +}; ``` -Once you have imported the emails you can resolve users in your [sign-in -resolver](../../auth/github/provider.md) using the catalog entity search via email +This example assumes you have implemented the custom transformer following the [Custom Transformers](#custom-transformers) and [Transformer Examples](#transformer-examples) documentation in the sections above. -```typescript title="packages/backend/src/plugins/auth.ts" +Once you have imported the emails you can resolve users by building a [Custom Resolver](../../auth/identity-resolver.md#building-custom-resolvers). In this custom resolver you can then use this example to properly match the user: + +```ts ctx.signInWithCatalogUser({ filter: { kind: ['User'], @@ -315,50 +257,3 @@ ctx.signInWithCatalogUser({ }, }); ``` - -## Using a Processor instead of a Provider - -An alternative to using the Provider for ingesting organizational entities is to -use a Processor. This is the old way that's based on registering locations with -the proper type and target, triggering the processor to run. - -The drawback of this method is that it will leave orphaned Group/User entities -whenever they are deleted on your GitHub server, and you cannot control the -frequency with which they are refreshed, separately from other processors. - -### Processor Installation - -The `GithubOrgReaderProcessor` is not registered by default, so you have to -install and register it in the catalog plugin: - -```bash -# From your Backstage root directory -yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github -``` - -```typescript title="packages/backend/src/plugins/catalog.ts" -import { GithubOrgReaderProcessor } from '@backstage/plugin-catalog-backend-module-github'; - -builder.addProcessor( - GithubOrgReaderProcessor.fromConfig(env.config, { logger: env.logger }), -); -``` - -### Processor Configuration - -The integration section of your app-config needs to be set up in the same way as -for the Entity Provider - see above. - -In addition to that, you typically want to add a few static locations to your -app-config, which reference your organizations to import. The following -configuration enables an import of the teams and users under the org -`https://github.com/my-org-name` on public GitHub. - -```yaml -catalog: - locations: - - type: github-org - target: https://github.com/my-org-name - rules: - - allow: [User, Group] -``` diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index 91efe05fee..b16f6db839 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -136,7 +136,11 @@ To use the discovery provider, you'll need a GitLab integration [set up](locations.md) with a `token`. Then you can add a provider config per group to the catalog configuration. -> > NOTE: if you are using the New Backend System, the `schedule` has to be setup in the config, as shown below. +:::note Note + +If you are using the New Backend System, the `schedule` has to be setup in the config, as shown below. + +::: ```yaml title="app-config.yaml" catalog: diff --git a/docs/integrations/gitlab/locations.md b/docs/integrations/gitlab/locations.md index a71fc9bcba..f5995a3ac1 100644 --- a/docs/integrations/gitlab/locations.md +++ b/docs/integrations/gitlab/locations.md @@ -19,9 +19,11 @@ integrations: token: ${GITLAB_TOKEN} ``` -> Note: A public GitLab provider is added automatically at startup for -> convenience, so you only need to list it if you want to supply a -> [token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html). +:::note Note + +A public GitLab provider is added automatically at startup for convenience, so you only need to list it if you want to supply a [token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html). + +::: Directly under the `gitlab` key is a list of provider configurations, where you can list the GitLab providers you want to fetch data from. Each entry is a diff --git a/docs/integrations/gitlab/org.md b/docs/integrations/gitlab/org.md index 14587461e5..2cc0dcfb82 100644 --- a/docs/integrations/gitlab/org.md +++ b/docs/integrations/gitlab/org.md @@ -158,7 +158,11 @@ amount of data, this can take significant time and resources. The token used must have the `read_api` scope, and the Users and Groups fetched will be those visible to the account which provisioned the token. -> > NOTE: if you are using the New Backend System, the `schedule` has to be setup in the config, as shown below. +:::note Note + +If you are using the New Backend System, the `schedule` has to be setup in the config, as shown below. + +::: ```yaml catalog: diff --git a/docs/integrations/harness/locations.md b/docs/integrations/harness/locations.md new file mode 100644 index 0000000000..a3d0e2cfd4 --- /dev/null +++ b/docs/integrations/harness/locations.md @@ -0,0 +1,33 @@ +--- +id: locations +title: Harness Locations +sidebar_label: Locations +description: Integrating source code stored in Harness Code into the Backstage catalog +--- + +The Harness Code integration supports loading catalog entities from a hosted repository. Entities can be added to +[static catalog configuration](../../features/software-catalog/configuration.md), +registered with the +[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import) +plugin. + +## Configuration + +To use this integration, add configuration to your root `app-config.yaml`: + +```yaml +integrations: + harness: + - host: app.harness.io + token: ${HARNESS_CODE_BEARER_TOKEN} + apiKey: ${HARNESS_CODE_APIKEY} +``` + +Directly under the `harness` key is a list of provider configurations, where you +can list the Harness instances you want to be able to fetch + +check out https://developer.harness.io/docs/platform/automation/api/add-and-manage-api-keys/ for more information + +- `host`: The host of the Harness Code instance that you want to match on. +- `token` (optional): The password or api token to authenticate with. +- `apiKey` (optional): The apiKey to authenticate with. diff --git a/docs/integrations/ldap/org--old.md b/docs/integrations/ldap/org--old.md new file mode 100644 index 0000000000..13fbcb9408 --- /dev/null +++ b/docs/integrations/ldap/org--old.md @@ -0,0 +1,417 @@ +--- +id: org--old +title: LDAP Organizational Data +sidebar_label: Org Data +# prettier-ignore +description: Setting up ingestion of organizational data from LDAP +--- + +The Backstage catalog can be set up to ingest organizational data - users and +groups - directly from an LDAP compatible service. The result is a hierarchy of +[`User`](../../features/software-catalog/descriptor-format.md#kind-user) and +[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind +entities that mirror your org setup. + +## Supported vendors + +Backstage in general supports OpenLDAP compatible vendors, as well as Active Directory and FreeIPA. If you are using a vendor that does not seem to be supported, please [file an issue](https://github.com/backstage/backstage/issues/new?assignees=&labels=enhancement&template=feature_template.md). + +## Installation + +This guide will use the Entity Provider method. If you for some reason prefer +the Processor method (not recommended), it is described separately below. + +The provider is not installed by default, therefore you have to add a dependency +to `@backstage/plugin-catalog-backend-module-ldap` to your backend package. + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-ldap +``` + +:::note Note + +When configuring to use a Provider instead of a Processor you do not +need to add a _location_ pointing to your LDAP server + +::: + +Update the catalog plugin initialization in your backend to add the provider and +schedule it: + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { LdapOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-ldap'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + /* highlight-add-start */ + // The target parameter below needs to match the ldap.providers.target + // value specified in your app-config. + builder.addEntityProvider( + LdapOrgEntityProvider.fromConfig(env.config, { + id: 'our-ldap-master', + target: 'ldaps://ds.example.net', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }), + ); + /* highlight-add-end */ + + // .. +} +``` + +After this, you also have to add some configuration in your app-config that +describes what you want to import for that target. + +## Configuration + +The following configuration is a small example of how a setup could look for +importing groups and users from a corporate LDAP server. + +```yaml +ldap: + providers: + - target: ldaps://ds.example.net + bind: + dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net + secret: ${LDAP_SECRET} + users: + dn: ou=people,ou=example,dc=example,dc=net + options: + filter: (uid=*) + map: + description: l + set: + metadata.customField: 'hello' + groups: + dn: ou=access,ou=groups,ou=example,dc=example,dc=net + options: + filter: (&(objectClass=some-group-class)(!(groupType=email))) + map: + description: l + set: + metadata.customField: 'hello' +``` + +There may be many providers, each targeting a specific `target` which is +supposed to match the `target` of a dedicated provider instance - i.e., you will +add one entity provider class instance per target to ingest from. + +These config blocks have a lot of options in them, so we will describe each +"root" key within the block separately. + +### target + +This is the URL of the targeted server, typically on the form +`ldaps://ds.example.net` for SSL enabled servers or `ldap://ds.example.net` +without SSL. + +#### target.tls.keys + +`keys` in TLS options specifies location of a file, that contains private keys +to establish connection with your LDAP server, in PEM format. See an example +for Google Secure LDAP Service below. + +#### target.tls.certs + +`certs` in TLS options specifies location of a file, that contains certificate +chains to establish connection with your LDAP server, in PEM format. See an +example for Google Secure LDAP Service below. + +### bind + +The bind block specifies how the plugin should bind (essentially, to +authenticate) towards the server. It has the following fields. + +```yaml +dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net +secret: ${LDAP_SECRET} +``` + +The `dn` is the full LDAP Distinguished Name for the user that the plugin +authenticates itself as. At this point, only regular user based authentication +is supported. + +The `secret` is the password of the same user. In this example, it is given in +the form of an environment variable `LDAP_SECRET`, that has to be set when the +backend starts. + +### users + +The `users` block defines the settings that govern the reading and +interpretation of users. Its fields are explained in separate sections below. + +#### users.dn + +The DN under which users are stored, e.g. +`ou=people,ou=example,dc=example,dc=net`. + +#### users.options + +The search options to use when sending the query to the server, when reading all +users. All the options are shown below, with their default values, but they are +all optional. + +```yaml +options: + # One of 'base', 'one', or 'sub'. + scope: one + # The filter is the one that you commonly will want to specify explicitly. It + # is a string on the standard LDAP query format. Use it to select out the set + # of users that are of actual interest to ingest. For example, you may want + # to filter out disabled users. + filter: (uid=*) + # The attribute selectors for each item, as passed to the LDAP server. + attributes: ['*', '+'] + # This field is either 'false' to disable paging when reading from the + # server, or an object on the form '{ pageSize: 100, pagePause: true }' that + # specifies the details of how the paging shall work. + paged: false +``` + +#### users.set + +This optional piece lets you specify a number of JSON paths (on a.b.c form) and +hard coded values to set on those paths. This can be useful for example if you +want to hard code a namespace or similar on the generated entities. + +```yaml +set: + # Just an example; the key and value can be anything + metadata.namespace: 'ldap' +``` + +#### users.map + +Mappings from well known entity fields, to LDAP attribute names. This is where +you are able to define how to interpret the attributes of each LDAP result item, +and to move them into the corresponding entity fields. All the options are shown +below, with their default values, but they are all optional. + +If you leave out an optional mapping, it will still be copied using that default +value. For example, even if you do not put in the field `displayName` in your +config, the provider will still copy the attribute `cn` into the entity field +`spec.profile.displayName`. + +```yaml +map: + # The name of the attribute that holds the relative + # distinguished name of each entry. + rdn: uid + # The name of the attribute that shall be used for the value of + # the metadata.name field of the entity. + name: uid + # The name of the attribute that shall be used for the value of + # the metadata.description field of the entity. + description: description + # The name of the attribute that shall be used for the value of + # the spec.profile.displayName field of the entity. + displayName: cn + # The name of the attribute that shall be used for the value of + # the spec.profile.email field of the entity. + email: mail + # The name of the attribute that shall be used for the value of + # the spec.profile.picture field of the entity. + picture: + # The name of the attribute that shall be used for the values of + # the spec.memberOf field of the entity. + memberOf: memberOf +``` + +### groups + +The `groups` block defines the settings that govern the reading and +interpretation of groups. Its fields are explained in separate sections below. + +#### groups.dn + +The DN under which groups are stored, e.g. +`ou=people,ou=example,dc=example,dc=net`. + +#### groups.options + +The search options to use when sending the query to the server, when reading all +groups. All the options are shown below, with their default values, but they are +all optional. + +```yaml +options: + # One of 'base', 'one', or 'sub'. + scope: one + # The filter is the one that you commonly will want to specify explicitly. It + # is a string on the standard LDAP query format. Use it to select out the set + # of groups that are of actual interest to ingest. For example, you may want + # to filter out disabled groups. + filter: (&(objectClass=some-group-class)(!(groupType=email))) + # The attribute selectors for each item, as passed to the LDAP server. + attributes: ['*', '+'] + # This field is either 'false' to disable paging when reading from the + # server, or an object on the form '{ pageSize: 100, pagePause: true }' that + # specifies the details of how the paging shall work. + paged: false +``` + +#### groups.set + +This optional piece lets you specify a number of JSON paths (on a.b.c form) and +hard coded values to set on those paths. This can be useful for example if you +want to hard code a namespace or similar on the generated entities. + +```yaml +set: + # Just an example; the key and value can be anything + metadata.namespace: 'ldap' +``` + +#### groups.map + +Mappings from well known entity fields, to LDAP attribute names. This is where +you are able to define how to interpret the attributes of each LDAP result item, +and to move them into the corresponding entity fields. All of the options are +shown below, with their default values, but they are all optional. + +If you leave out an optional mapping, it will still be copied using that default +value. For example, even if you do not put in the field `displayName` in your +config, the provider will still copy the attribute `cn` into the entity field +`spec.profile.displayName`. If the target field is optional, such as the display +name, the importer will accept missing attributes and just leave the target +field unset. If the target field is mandatory, such as the name of the entity, +validation will fail if the source attribute is missing. + +```yaml +map: + # The name of the attribute that holds the relative + # distinguished name of each entry. This value is copied into a + # well known annotation to be able to query by it later. + rdn: cn + # The name of the attribute that shall be used for the value of + # the metadata.name field of the entity. + name: cn + # The name of the attribute that shall be used for the value of + # the metadata.description field of the entity. + description: description + # The name of the attribute that shall be used for the value of + # the spec.type field of the entity. + type: groupType + # The name of the attribute that shall be used for the value of + # the spec.profile.displayName field of the entity. + displayName: cn + # The name of the attribute that shall be used for the value of + # the spec.profile.email field of the entity. + email: + # The name of the attribute that shall be used for the value of + # the spec.profile.picture field of the entity. + picture: + # The name of the attribute that shall be used for the values of + # the spec.parent field of the entity. + memberOf: memberOf + # The name of the attribute that shall be used for the values of + # the spec.children field of the entity. + members: member +``` + +## Customize the Provider + +In case you want to customize the ingested entities, the provider allows to pass +transformers for users and groups. Here we will show an example of overriding +the group transformer. + +1. Create a transformer: + + ```ts + export async function myGroupTransformer( + vendor: LdapVendor, + config: GroupConfig, + group: SearchEntry, + ): Promise { + // Transformations may change namespace, change entity naming pattern, fill + // profile with more or other details... + + // Create the group entity on your own, or wrap the default transformer + return await defaultGroupTransformer(vendor, config, group); + } + ``` + +2. Configure the provider with the transformer: + + ```ts + const ldapEntityProvider = LdapOrgEntityProvider.fromConfig(env.config, { + id: 'our-ldap-master', + target: 'ldaps://ds.example.net', + logger: env.logger, + groupTransformer: myGroupTransformer, + }); + ``` + +## Using a Processor instead of a Provider + +An alternative to using the Provider for ingesting LDAP entries is to use a +Processor. This is the old way that's based on registering locations with the +proper type and target, triggering the processor to run. + +The drawback of this method is that it will leave orphaned Group/User entities +whenever they are deleted on your LDAP server, and you cannot control the +frequency with which they are refreshed, separately from other processors. + +### Processor Installation + +The `LdapOrgReaderProcessor` is not registered by default, so you have to +register it in the catalog plugin: + +```typescript title="packages/backend/src/plugins/catalog.ts" +builder.addProcessor( + LdapOrgReaderProcessor.fromConfig(env.config, { + logger: env.logger, + }), +); +``` + +### Driving LDAP Org Processor Ingestion with Locations + +Locations point out the specific org(s) you want to import. The `type` of these +locations must be `ldap-org`, and the `target` must point to the exact URL +(starting with `ldap://` or `ldaps://`) of the targeted LDAP server. You can +have several such location entries if you want, but typically you will have just +one. + +```yaml +catalog: + locations: + - type: ldap-org + target: ldaps://ds.example.net + rules: + - allow: [User, Group] +``` + +### Example configurations + +#### Google Secure LDAP Service + +To sync Google Workspace/Cloud Identity organization data to users and groups in backstage, +you must [configure Secure LDAP Service](https://support.google.com/a/answer/9048516) first. + +Once Secure LDAP Service is configured, you can enable TLS options in LDAP configuration, +as mentioned below. `keys` and `certs` specify the location of files that are generated +while configuring Secure LDAP Service above. + +```yaml +ldap: + providers: + - target: ldaps://ldap.google.com:636 + tls: + rejectUnauthorized: false + keys: '/var/secrets/tls/gldap.key' + certs: '/var/secrets/tls/gldap.crt' + users: + # users configuration comes here + groups: + # groups configuration comes here +``` diff --git a/docs/integrations/ldap/org.md b/docs/integrations/ldap/org.md index 49a2776fb1..f70d02afed 100644 --- a/docs/integrations/ldap/org.md +++ b/docs/integrations/ldap/org.md @@ -18,9 +18,6 @@ Backstage in general supports OpenLDAP compatible vendors, as well as Active Dir ## Installation -This guide will use the Entity Provider method. If you for some reason prefer -the Processor method (not recommended), it is described separately below. - The provider is not installed by default, therefore you have to add a dependency to `@backstage/plugin-catalog-backend-module-ldap` to your backend package. @@ -29,43 +26,30 @@ to `@backstage/plugin-catalog-backend-module-ldap` to your backend package. yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-ldap ``` -> Note: When configuring to use a Provider instead of a Processor you do not -> need to add a _location_ pointing to your LDAP server +Next add the basic configuration to `app-config.yaml` -Update the catalog plugin initialization in your backend to add the provider and -schedule it: - -```ts title="packages/backend/src/plugins/catalog.ts" -/* highlight-add-next-line */ -import { LdapOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-ldap'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - - /* highlight-add-start */ - // The target parameter below needs to match the ldap.providers.target - // value specified in your app-config. - builder.addEntityProvider( - LdapOrgEntityProvider.fromConfig(env.config, { - id: 'our-ldap-master', - target: 'ldaps://ds.example.net', - logger: env.logger, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 60 }, - timeout: { minutes: 15 }, - }), - }), - ); - /* highlight-add-end */ - - // .. -} +```yaml title="app-config.yaml" +catalog: + providers: + ldapOrg: + default: + target: ldaps://ds.example.net + bind: + dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net + secret: ${LDAP_SECRET} + schedule: + frequency: PT1H + timeout: PT15M ``` -After this, you also have to add some configuration in your app-config that -describes what you want to import for that target. +Finally, updated your backend by adding the following line: + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-catalog-backend-module-ldap')); +/* highlight-add-end */ +``` ## Configuration @@ -73,34 +57,32 @@ The following configuration is a small example of how a setup could look for importing groups and users from a corporate LDAP server. ```yaml -ldap: +catalog: providers: - - target: ldaps://ds.example.net - bind: - dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net - secret: ${LDAP_SECRET} - users: - dn: ou=people,ou=example,dc=example,dc=net - options: - filter: (uid=*) - map: - description: l - set: - metadata.customField: 'hello' - groups: - dn: ou=access,ou=groups,ou=example,dc=example,dc=net - options: - filter: (&(objectClass=some-group-class)(!(groupType=email))) - map: - description: l - set: - metadata.customField: 'hello' + ldapOrg: + default: + target: ldaps://ds.example.net + bind: + dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net + secret: ${LDAP_SECRET} + users: + dn: ou=people,ou=example,dc=example,dc=net + options: + filter: (uid=*) + map: + description: l + set: + metadata.customField: 'hello' + groups: + dn: ou=access,ou=groups,ou=example,dc=example,dc=net + options: + filter: (&(objectClass=some-group-class)(!(groupType=email))) + map: + description: l + set: + metadata.customField: 'hello' ``` -There may be many providers, each targeting a specific `target` which is -supposed to match the `target` of a dedicated provider instance - i.e., you will -add one entity provider class instance per target to ingest from. - These config blocks have a lot of options in them, so we will describe each "root" key within the block separately. @@ -317,97 +299,34 @@ map: ## Customize the Provider In case you want to customize the ingested entities, the provider allows to pass -transformers for users and groups. Here we will show an example of overriding -the group transformer. +transformers for users and groups. -1. Create a transformer: +Transformers can be configured by extending `ldapOrgEntityProviderTransformExtensionPoint`. Here is an example: - ```ts - export async function myGroupTransformer( - vendor: LdapVendor, - config: GroupConfig, - group: SearchEntry, - ): Promise { - // Transformations may change namespace, change entity naming pattern, fill - // profile with more or other details... +```ts title="packages/backend/src/index.ts" +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { ldapOrgEntityProviderTransformExtensionPoint } from '@backstage/plugin-catalog-backend-module-ldap'; +import { myUserTransformer, myGroupTransformer } from './transformers'; - // Create the group entity on your own, or wrap the default transformer - return await defaultGroupTransformer(vendor, config, group); - } - ``` - -2. Configure the provider with the transformer: - - ```ts - const ldapEntityProvider = LdapOrgEntityProvider.fromConfig(env.config, { - id: 'our-ldap-master', - target: 'ldaps://ds.example.net', - logger: env.logger, - groupTransformer: myGroupTransformer, - }); - ``` - -## Using a Processor instead of a Provider - -An alternative to using the Provider for ingesting LDAP entries is to use a -Processor. This is the old way that's based on registering locations with the -proper type and target, triggering the processor to run. - -The drawback of this method is that it will leave orphaned Group/User entities -whenever they are deleted on your LDAP server, and you cannot control the -frequency with which they are refreshed, separately from other processors. - -### Processor Installation - -The `LdapOrgReaderProcessor` is not registered by default, so you have to -register it in the catalog plugin: - -```typescript title="packages/backend/src/plugins/catalog.ts" -builder.addProcessor( - LdapOrgReaderProcessor.fromConfig(env.config, { - logger: env.logger, +backend.add( + createBackendModule({ + pluginId: 'catalog', + moduleId: 'ldap-extensions', + register(env) { + env.registerInit({ + deps: { + /* highlight-add-start */ + ldapTransformers: ldapOrgEntityProviderTransformExtensionPoint, + /* highlight-add-end */ + }, + async init({ ldapTransformers }) { + /* highlight-add-start */ + ldapTransformers.setUserTransformer(myUserTransformer); + ldapTransformers.setGroupTransformer(myGroupTransformer); + /* highlight-add-end */ + }, + }); + }, }), ); ``` - -### Driving LDAP Org Processor Ingestion with Locations - -Locations point out the specific org(s) you want to import. The `type` of these -locations must be `ldap-org`, and the `target` must point to the exact URL -(starting with `ldap://` or `ldaps://`) of the targeted LDAP server. You can -have several such location entries if you want, but typically you will have just -one. - -```yaml -catalog: - locations: - - type: ldap-org - target: ldaps://ds.example.net - rules: - - allow: [User, Group] -``` - -### Example configurations - -#### Google Secure LDAP Service - -To sync Google Workspace/Cloud Identity organization data to users and groups in backstage, -you must [configure Secure LDAP Service](https://support.google.com/a/answer/9048516) first. - -Once Secure LDAP Service is configured, you can enable TLS options in LDAP configuration, -as mentioned below. `keys` and `certs` specify the location of files that are generated -while configuring Secure LDAP Service above. - -```yaml -ldap: - providers: - - target: ldaps://ldap.google.com:636 - tls: - rejectUnauthorized: false - keys: '/var/secrets/tls/gldap.key' - certs: '/var/secrets/tls/gldap.crt' - users: - # users configuration comes here - groups: - # groups configuration comes here -``` diff --git a/docs/openapi/generate-client.md b/docs/openapi/generate-client.md index 640036960e..b8acc331e5 100644 --- a/docs/openapi/generate-client.md +++ b/docs/openapi/generate-client.md @@ -20,7 +20,7 @@ info: ### Generating your client -1. Run `yarn backstage-repo-tools schema openapi generate client --output-package `. This will create a new folder in `/src/generated` to house the generated content. +1. Run `yarn backstage-repo-tools package schema openapi generate client --client-package `. This will create a new folder in `/src/generated` to house the generated content. 2. You should use the generated files as follows, - `apis/DefaultApi.client.ts` - this is the client that you should use. It has types for all of the various operations on your API. diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md index 8e3d73ded6..1a41eedd63 100644 --- a/docs/overview/roadmap.md +++ b/docs/overview/roadmap.md @@ -6,93 +6,87 @@ description: Roadmap of Backstage ## The Backstage Roadmap -Backstage is currently under rapid development. This page details the project's -public roadmap, the result of ongoing collaboration between the core maintainers -and the broader Backstage community. +Backstage is still under rapid development, and this page details the project's +public roadmap. This not a complete list of all work happening in and around the +project, it only highlights the highest priority initiatives worked on by the +core maintainers. -The Backstage roadmap lays out both [“what's next”](#whats-next) and ["future -work"](#future-work). With "next" we mean features planned for release within -the ongoing quarter from July through September 2022. With "future" we mean -features on the radar, but not yet scheduled. +## 2024 Fall Roadmap -| [What's next](#whats-next) | [Future work](#future-work) | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -| [Backend Services (MVP)](#backend-services-mvp)
[Backstage Security Audit](#backstage-security-audit)
[Backstage Threat Model](#backstage-threat-model)
[Software Catalog pagination](#software-catalog-pagination)
[More SIGs](#more-sigs) | Ease of onboarding
Composable Homepage 1.0
Creator experience
GraphQL
Telemetry | +The initiatives listed below are planned for release within the next half-year, starting in May 2024. The roadmap is updated every 6 months, and the next update is planned for November 2024. -The long-term roadmap (12 - 36 months) is not detailed in the public roadmap. -Third-party contributions are also not currently included in the roadmap. Let us -know about any ongoing developments and we're happy to include them here as -well. +### Backend System 1.0 -## What's next +The goal of this initiative is the stable 1.0 release of the [new backend system](../backend-system/index.md). +This includes ensuring that all documentation is up to date, and includes API +reviews and refactoring efforts to ensure that what is released is both stable +and evolvable. You can follow along with this work in the [meta issue](https://github.com/backstage/backstage/issues/24493). -The feature set below is planned for the ongoing quarter, and grouped by theme. -The list order doesn't necessarily reflect priority, and the development/release -cycle will vary based on maintainer schedules. +As part of this initiative, there will also be an exploration on how to +simplify extension of backend services. It is not currently possible to augment +backend services through declarative integration, they are instead only +customizable through complete replacement. This also limits the ability to +modularize services and scale ownership of the implementations. The goal is to +provide a more flexible and scalable way to extend backend services. -### Backend Services (MVP) +### New Frontend System - Ready for Adoption -To better scale and maintain the Backstage instances, a backend services system -is planned to be introduced as part of the software architecture. This layer of -backend services will help in decoupling the various modules (e.g. Catalog and -Scaffolder) from the frontend experience. +The [new fronted system](../frontend-system/index.md) still needs more work, and +the next milestone is to improve it to the point where there is enough +confidence in the design to start encouraging adoption in the community. You can +follow along with this work in the [meta issue](https://github.com/backstage/backstage/issues/19545). +This milestone also includes reaching and executing [rollout phase 2](https://github.com/backstage/backstage/issues/19545#issuecomment-1766069146). -After the experimentation and design happened in the past quarter, soon we plan to release a first version to start providing the first benefits to adopters and developers. +Once the initial milestone is reached, the goal is to also build out broader +support for the new frontend system in the core plugins. ### Backstage Security Audit -This is the continuation of the initiative started in the previous quarters. This -quarter will see the publication of the report describing the outcome of the -audit, together the first fixes and the development of some of the changes -required to address the vulnerabilities. +This is the second security audit of the Backstage project. It is done together, +and with the support of the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/). +This time the audit will in particular focus on the recently introduced +[authentication system](https://github.com/backstage/backstage/tree/master/beps/0003-auth-architecture-evolution), +but also cover other parts of the project. -This initiative is the first of a broader Security Strategy for Backstage. The -purpose of the Security Audit is to involve third-party companies in auditing -the platform. The benefit for the adopters is clear: we want Backstage to be as -secure as possible, and we want to make it reliable through a specific -initiative. +### Plugin Metadata -This initiative is done together with, and with the support of, the [Cloud -Native Computing Foundation (CNCF)](https://www.cncf.io/). +The goal of this initiative is to provide better machine readable metadata for +Backstage packages, available both at runtime, at build-time and as part of +package registries. We want to surface information such as what packages make up +a particular plugin, what features it provides, and more generally laying the +foundation for an evolvable plugin metadata system. -### Backstage Threat Model +### MUI v5 Green-light -This is another (relevant) initiative planned to make Backstage a secure product for the adopters. The goals of this initiative are: +Material-UI v4 is still the officially supported version of MUI in Backstage. +While we have heard that adopters have had success using MUI 5, this is still an +untested path with known bugs. The goal of this initiative is to iron out any +remaining issues or gaps, and then provide a green light for migration to MUI 5. -1. Understand where security investment and attention is needed. -2. Guide the upcoming security audit. -3. Communicate expectations to Backstage adopters and inform and attract security researchers. +### Configuration Improvements -The planned artifacts are: +This initiative aims to improve the configuration experience and reliability in +Backstage. Areas for improvement include the way that configuration schema is +loaded, the way that plugins access configuration that is not owned by them, how +plugins read configuration, and how configuration visibility is handled. -- Concise high level threat model that will be included as part of the Backstage security documentation. -- Granular threat model created in conjunction with the security audit to inform further security investment areas for Backstage. +### Versioned Documentation -### Software Catalog pagination +The goal of this initiative is to provide versioned documentation at +[backstage.io](https://backstage.io). This lets us provide documentation that is +both up-to-date while at the same time not ahead of the latest release. -Today adopters with a big catalog (with several thousands of software components) might not have an ideal end-user experience when viewing the `/catalog` page. The issue is related to how the entities are fetched by the frontend. In order to provide a better end-user experience the pagination of the catalog’s entities needs to be enforced. Some experimentation is already completed but in this quarter we plan to continue, and hopefully complete, this relevant enhancement. +### Rework Pull Request & Issue Process -### More SIGs +Our current review and issue triage process is centered around either core- or +project area maintainers. The goal of this initiative is to make it simpler for +more members of the community to be involved and contribute to this process. -In the last quarter we launched the [Catalog SIG (Special Interest Group)](https://github.com/backstage/community/tree/main/sigs/sig-catalog) to better coordinate the increasing number of contributions to the project. We think that this is the proper path to follow to engage more with the contributors. For this reason we will launch other SIGs dedicated to the most interesting topics for the community. +### Catalog Observability -## Future work - -The following feature list doesn't represent a commitment to develop, and the -list order doesn't reflect any priority or importance, but these features are on -the maintainers' radar, with clear interest expressed by the community. - -- **Ease of onboarding:** A faster (with less development) and easier setup of - Backstage and the most relevant/adopted plugins. -- **Composable Homepage 1.0:** Driving this to 1.0 by adding some composable - components. -- **Creator experience:** Provide a better Backstage user experience through - visual guidelines and templates, especially navigation across plug-ins and - portal functionalities. -- **[GraphQL](https://graphql.org/) support:** Introduce the ability to query - Backstage backend services with a standard query language for APIs. -- **Telemetry:** To efficiently generate logging and metrics in such a way that - adopters can get insights so that Backstage can be monitored and improved. +The goal of this initiative is to provide better tools for debugging catalog +ingestion issues and to more generally reduce friction for setting up and +maintaining the software catalog. ## How to influence the roadmap diff --git a/docs/overview/threat-model.md b/docs/overview/threat-model.md index 442d51985c..da97f3fc83 100644 --- a/docs/overview/threat-model.md +++ b/docs/overview/threat-model.md @@ -14,21 +14,28 @@ The Backstage trust model is divided into three groups with different trust leve An **internal user** is an authenticated user that generally belongs to the organization of a particular Backstage deployment. These users are trusted to the extent that they are not expected to compromise the availability of Backstage, but they are not trusted to not compromise data confidentiality or integrity. -An **integrator** is a user responsible for configuring and maintaining an instance of Backstage. Integrators are fully trusted, since they operate the system and database and therefore have root access to the host system. Additional measures can be taken by adopters of Backstage in order to restrict or observe the access of this group, but that falls outside of the current scope of Backstage. +An **operator** is a user responsible for configuring and maintaining an instance of Backstage. Operators are fully trusted, since they operate the system and database and therefore have root access to the host system. Additional measures can be taken by adopters of Backstage in order to restrict or observe the access of this group, but that falls outside of the current scope of Backstage. -Another group of de facto integrators is internal and external code contributors. When installing Backstage plugins you should vet them just like any other package from an external source. While it’s possible to limit the impact of for example a supply chain attack by splitting the deployment into separate services with different plugins, the Backstage project itself does not aim to prevent these kinds of attacks or in any other way sandbox or limit the access of plugins. +A **builder** is an internal or external code contributor and end up having a similar level of access as operators. When installing Backstage plugins you should vet them just like any other package from an external source. While it’s possible to limit the impact of for example a supply chain attack by splitting the deployment into separate services with different plugins, the Backstage project itself does not aim to prevent these kinds of attacks or in any other way sandbox or limit the access of plugins. An **external user** is a user that does not belong to the other two groups, for example a malicious actor outside of the organization. The security model of Backstage currently assumes that this group does not have any direct access to Backstage, and it is the responsibility of each adopter of Backstage to make sure this is the case. -## Integrator Responsibilities +## Operator Responsibilities -As an integrator of Backstage you yourself are responsible for protecting your Backstage installation from external and unauthorized access. The sign-in system in Backstage does not exist to limit access, only to inform the system of the identity of the user. There are some plugins that have more fine-grained access control through the permissions system, but the primary purpose of that system is to restrict access to resources for internal users rather than Backstage as a whole. A common and recommended way to protect a Backstage deployment from unauthorized access is to deploy it behind an authenticating proxy such as AWS’s ALB, GCP’s IAP, or Cloudflare Access. +:::info +This section assumes that you are using the +[new backend system](../backend-system/index.md) and at least Backstage release [version 1.24](../releases/v1.24.0.md). Before that Backstage did not come with built-in protection against unauthorized access and you were required to deploy it in a protected environment. +::: -Other responsibilities include protecting the integrity of configuration files as it may otherwise be possible to introduce vulnerable configurations, as well as the confidentiality of configured secrets related to Backstage as these typically include authentication details to third party systems. +Backstage is primarily designed to be deployed in a protected environment rather than being exposed to the public internet. From a confidentiality and integrity perspective, Backstage is designed to protect against unauthorized access to data and to ensure that data is not tampered with. However, Backstage does not provide more than rudimentary protection against denial of service attacks, and it is the responsibility of the operator to ensure that the Backstage deployment is protected against such attacks. A common and recommended way to protect a Backstage deployment from unauthorized access is to deploy it behind an authenticating proxy such as AWS’s ALB, GCP’s IAP, or Cloudflare Access. -The integrator is ultimately responsible for auditing usage of internal and external plugins as these run on the host system and have access to configuration and secrets. When installing plugins from sources like NPM, you should vet these in the same way that you would vet any other package installed from that source. +Users that are signed-in in to Backstage generally have full access to all information and actions. If more fine-grained control is required, the [permissions system](../permissions/overview.md) should be enabled and configured to restrict access as necessary. -The integrator is also responsible for maintaining the resolved NPM dependencies of their Backstage project. This involves ensuring that `yarn.lock` receives updated versions of packages that have vulnerabilities, when those fixed versions are in range of what the Backstage packages request in their respective `package.json` files. This is commonly done by employing automated tooling such as [Dependabot](https://dependabot.com/), [Snyk](https://snyk.io/), and/or [Renovate](https://docs.renovatebot.com/) on your own repository. When fixed versions exist that are _not_ in range of what Backstage packages request, or when larger operations such as switching out an entire dependency for another one is required, maintainers collaborate with contributors to try to address those dependency declarations in the main project as soon as possible. +An operator is responsible for protecting the integrity of configuration files as it may otherwise be possible to introduce vulnerable configurations, as well as the confidentiality of configured secrets related to Backstage as these typically include authentication details to third party systems. + +The operator is ultimately responsible for auditing usage of internal and external plugins as these run on the host system and have access to configuration and secrets. When installing plugins from sources like NPM, you should vet these in the same way that you would vet any other package installed from that source. + +The operator is also responsible for maintaining the resolved NPM dependencies of their Backstage project. This involves ensuring that `yarn.lock` receives updated versions of packages that have vulnerabilities, when those fixed versions are in range of what the Backstage packages request in their respective `package.json` files. This is commonly done by employing automated tooling such as [Dependabot](https://dependabot.com/), [Snyk](https://snyk.io/), and/or [Renovate](https://docs.renovatebot.com/) on your own repository. When fixed versions exist that are _not_ in range of what Backstage packages request, or when larger operations such as switching out an entire dependency for another one is required, maintainers collaborate with contributors to try to address those dependency declarations in the main project as soon as possible. ## Common Backend Configuration @@ -44,21 +51,23 @@ Note that the `UrlReader` system operates with a service context and is not inte Backstage provides authentication of users through the `auth` plugin, which primarily acts as an authorization server for different OAuth 2.0 provider integrations. These integrations can both serve the purpose of signing users into Backstage, as well as providing delegated access to external resources, and are all subject to the common concerns of implementing secure OAuth 2.0 authorization servers. All auth provider integrations are disabled by default, and need to be enabled through configuration in order to be used. For each Backstage installation it is recommended to only enable the minimal set of providers that are in use by that instance. -It is not within scope of the `auth` backend to protect against unauthorized access, that is something that needs to be handled at a deployment level. See the [Integrator Responsibilities](#integrator-responsibilities) section for more information. - In order to use an auth provider to sign in users into Backstage, it needs to be configured with an [Identity resolver](https://backstage.io/docs/auth/identity-resolver), which is a custom callback implemented in code. The identity resolver is a sensitive part of configuring Backstage and it is important that it always resolves user identities correctly, based on information provided by the authentication provider. There are a number of built-in identity resolvers that can simplify configuration, and it is important that these all resolve users in a secure way, regardless of how they are used. +Backstage also supports authentication through an authenticating reverse proxy such as [AWS ALB](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/), where the user identity is read from the incoming proxied decorated request. The following proxy auth providers verify the signature of incoming requests, and are therefore safe to deploy with direct access by users: `awsAlb`, `cfAccess`, and `gcpIap`. Providers like `oauth2Proxy` do not verify the incoming request and can therefore be spoofed by a malicious internal user to supply the `auth` backend with forged identity information. It’s therefore highly recommended to restrict access to the `oauth2Proxy` endpoints, or use a different provider. + As part of signing in with an identity resolver, a Backstage Token is issued containing the resolved user identity. The tokens are asymmetrically signed JSON Web Tokens, with the public keys available to any service that wishes to verify a token. The signing keys are rotated continuously and are unique to each installation of Backstage, meaning that Backstage Tokens are not shared across installations. The token contains claims for the user identity and ownership information, which can be used to determine what Backstage resources are owned by that user or group. It is important that this token can not be forged outside of the `auth` plugin, with the exception of other plugins deployed in the same backend service or sharing the same database. For a high-security deployment, the `auth` backend should therefore be deployed in a separate service with its own database. The token is used to prove the identity of the user within the Backstage system, and is used throughout Backstage plugins to control access. It is important that the ownership resolution logic is consistent across the entire Backstage ecosystem, with no possibility of misinterpreting the ownership information. -For cross-backend communication, the Backstage Token is typically forwarded or, in strict backend-to-backend communication without a user party, the backend itself issues a service token based on a pre-shared secret which is then validated on the receiving end. There are no unique service identities tied to these tokens at this point, meaning the tokens can be used across all services in a Backstage installation. This is something that we aim to improve in the future. +One of the claims in a user token is the User Identity Proof or `uip`. This is an additional signature of the token that allows for offline token transformation. By replacing the original signature with the `uip` the token is still proof of a user identity, but it no longer acts as a full access token and will be rejected by most plugin endpoints. Plugins can explicitly allow use of this limited token where required, but this should only be used when necessary when a full token is not available, and ideally just for read-only access. Use-cases for limited users tokens include cookie authentication of static assets, storage of user identity proofs in a database, and similar. -Backstage also supports authentication through a proxy where the user identity is read from the incoming request from the proxy, which has been decorated by an authenticating reverse proxy such as [AWS ALB](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/). The following proxy auth providers verify the signature of incoming requests, and are therefore safe to deploy with direct access by users: `awsAlb`, `cfAccess`, and `gcpIap`. Providers like `oauth2Proxy` does not verify the incoming request and can therefore be spoofed by a malicious internal user to supply the `auth` backend with forged identity information. It’s therefore highly recommended to restrict access to the `oauth2Proxy` endpoints, or use a different provider. +The communication across backend plugins uses a similar authentication scheme to the user authentication. Each backend plugin generates and publishes its own set of keys that it uses to sign its tokens, and the public keys are shared with all other plugins for verification. The expected location of each plugin's published JWKS is determined by the `DiscoveryService` implementation in the backend, which means that it is vital for any custom implementation of that service to be careful with user input. The tokens signed by each plugin contain both the source and target plugin ID, which means that the token can not be reused to access other plugins. + +When forwarding a user identity in a call across backend plugins only the limited user token with `uip` is used, wrapped in a new service token that is signed by the calling plugin. This means that the receiving plugin can trust the user identity, but it is not able to make further calls on behalf of the user except for with the plugins that it is authorized to call. That is except for any endpoints in other plugins that accept limited user tokens, which is a reason to avoid accepting them when possible. ## Catalog -Integrators should configure [catalog rules](https://backstage.io/docs/features/software-catalog/configuration#catalog-rules) to limit the allowed entity kinds that users can define. In general it is best to restrict definition of User, Group, and Template entities so that internal users cannot register additional ones. Template entities define actions that are executed on the backend hosts, and while the goal is for these actions to be secure regardless of input, it is still a more sensitive context and it is recommended that you protect it with additional checks. It is very important to not allow registration of User and Group entities if you ingest and rely on these as organizational data in your catalog. Doing so could otherwise open up for the ability to impersonate users and confuse group membership information. You should always ingest organizational data using a statically configured catalog location or an entity provider reading from a trusted source. The entities emitted directly by an entity provider are always trusted and rules are not applied to them, but any entities produced further down the chain are still subject to the rules. +Operators should configure [catalog rules](https://backstage.io/docs/features/software-catalog/configuration#catalog-rules) to limit the allowed entity kinds that users can define. In general it is best to restrict definition of User, Group, and Template entities so that internal users cannot register additional ones. Template entities define actions that are executed on the backend hosts, and while the goal is for these actions to be secure regardless of input, it is still a more sensitive context and it is recommended that you protect it with additional checks. It is very important to not allow registration of User and Group entities if you ingest and rely on these as organizational data in your catalog. Doing so could otherwise open up for the ability to impersonate users and confuse group membership information. You should always ingest organizational data using a statically configured catalog location or an entity provider reading from a trusted source. The entities emitted directly by an entity provider are always trusted and rules are not applied to them, but any entities produced further down the chain are still subject to the rules. The Catalog does not aim to protect against resource exhaustion attacks in its default setup. If you need to prevent your internal users from being able to register large amounts of entities, then it is recommended to disable entity registration and use a different approach for discovering entities. One way to mitigate any resource exhaustion attacks is to only allow the catalog to read from trusted SCM sources that have an audit trail. Catalog currently lacks limits for entity hierarchy depth and entity size, which we hope to address in the future. @@ -68,11 +77,11 @@ By default all internal users are allowed to create and delete entities. If this By default, Scaffolding jobs execute directly on the host machine, including any actions defined in the template. Because the Scaffolder templates are considered a more sensitive area it is recommended to control access to create and update templates to trusted parties. Template execution is intended to be secure regardless of input, but we still recommend this additional layer of protection. The string templating is executed in a [node VM sandbox](https://github.com/laverdet/isolated-vm) to mitigate the possibility of remote code execution attacks. -The Scaffolder often has elevated permissions to for example create repositories in a Github organization. The integrator should therefore be cautious of Scaffolder Templates that for example delete or update existing resources as the user input is typically user defined and can therefore delete or modify resources maliciously or by mistake. +The Scaffolder often has elevated permissions to for example create repositories in a Github organization. The operator should therefore be cautious of Scaffolder Templates that for example delete or update existing resources as the user input is typically user defined and can therefore delete or modify resources maliciously or by mistake. One strategy that allows you to reduce the access that the Scaffolder service has is to rely on user credentials when executing actions. For example, a GitHub App integration could be configured with read-only permissions, with a separate user OAuth token used to create repositories. This requires that your users have access to create repositories in the first place. -The integrator should audit installed scaffolding actions just like any other plugin package. It is also important to verify that installed actions fall in line with your own security requirements, as some actions might be intended for more relaxed environments. +The operator should audit installed scaffolding actions just like any other plugin package. It is also important to verify that installed actions fall in line with your own security requirements, as some actions might be intended for more relaxed environments. By default all internal users are allowed to execute templates in the scaffolder. If this does not fit your organization's needs it is recommended to enable and configure the [permission](https://backstage.io/docs/permissions/overview) system to restrict these operations. diff --git a/docs/overview/versioning-policy.md b/docs/overview/versioning-policy.md index 0b1bc975bd..2ae73e1383 100644 --- a/docs/overview/versioning-policy.md +++ b/docs/overview/versioning-policy.md @@ -81,19 +81,21 @@ In order for Backstage to function properly the following versioning rules must be followed. The rules are referring to the [Package Architecture](https://backstage.io/docs/overview/architecture-overview#package-architecture). -- The versions of all the packages in the `Frontend App Core` must be from the - same release, and it is recommended to keep `Common Tooling` on that release - too. -- The Backstage dependencies of any given plugin should be from the same - release. This includes the packages from `Common Libraries`, - `Frontend Plugin Core`, and `Frontend Libraries`, or alternatively the - `Backend Libraries`. -- There must be no package that is from a newer release than the - `Frontend App Core` packages in the app. +- The versions of all packages for each of the "App Core" groups must be from the + same Backstage release. +- For each frontend and backend setup, the "App Core" packages must be ahead of or on the same Backstage release as the "Plugin Core" packages, including transitive dependencies of all installed plugins and modules. +- For any given plugin, the versions of all packages from the "Plugin Core" and + "Library" groups must be from the same Backstage release. - Frontend plugins with a corresponding backend plugin should be from the same release. The update to the backend plugin **MUST** be deployed before or together with the update to the frontend plugin. +It is allowed and often expected that the "Plugin Core" and "Library" packages +are from older releases than the "App Core" packages. It is also allowed to have +duplicate installations of the "Plugin Core" and "Library" packages. This is all +to make sure that upgrading Backstage is as smooth as possible and allows for +more flexibility across the entire plugin ecosystem. + ## Package Versioning Policy Every individual package is versioned according to [semver](https://semver.org). diff --git a/docs/permissions/getting-started--new.md b/docs/permissions/getting-started--new.md new file mode 100644 index 0000000000..b6198a222f --- /dev/null +++ b/docs/permissions/getting-started--new.md @@ -0,0 +1,36 @@ +--- +id: getting-started--new +title: Getting Started +description: How to get started with the permission framework as an integrator +--- + +Backstage integrators control permissions by writing a policy. In general terms, a policy is simply an async function which receives a request to authorize a specific action for a user and (optional) resource, and returns a decision on whether to authorize that permission. Integrators can implement their own policies from scratch, or adopt reusable policies written by others. + +## Prerequisites + +The permissions framework depends on a few other Backstage systems, which must be set up before we can dive into writing a policy. + +### Upgrade to the latest version of Backstage + +To ensure your version of Backstage has all the latest permission-related functionality, it’s important to upgrade to the latest version. The [Backstage upgrade helper](https://backstage.github.io/upgrade-helper/) is a great tool to help ensure that you’ve made all the necessary changes during the upgrade! + +### Supply an identity resolver to populate group membership on sign in + +**Note**: If you are working off of an existing Backstage instance, you likely already have some form of an identity resolver set up. + +Like many other parts of Backstage, the permissions framework relies on information about group membership. This simplifies authoring policies through the use of groups, rather than requiring each user to be listed in the configuration. Group membership is also often useful for conditional permissions, for example allowing permissions to act on an entity to be granted when a user is a member of a group that owns that entity. + +[The IdentityResolver docs](../auth/identity-resolver.md) describe the process for resolving group membership on sign in. + +## Enable and test the permissions system + +All you need to do now is enable the permissions system in your Backstage instance! + +1. Set the property `permission.enabled` to `true` in `app-config.yaml`. + +```yaml title="app-config.yaml" +permission: + enabled: true +``` + +Congratulations! Now that the framework is configured, you can craft a permission policy that works best for your organization by utilizing a provided authorization method or by [writing your own policy](./writing-a-policy.md)! diff --git a/docs/permissions/getting-started.md b/docs/permissions/getting-started.md index e241f0e38e..4dabf3fcbd 100644 --- a/docs/permissions/getting-started.md +++ b/docs/permissions/getting-started.md @@ -8,7 +8,11 @@ If you prefer to watch a video instead, you can start with this video introducti -> Note: This video was recorded in the January 2022 Contributors Session using `@backstage/create-app@0.4.14`. Some aspects of the demo may have changed in later releases. +:::note Note + +This video was recorded in the January 2022 Contributors Session using `@backstage/create-app@0.4.14`. Some aspects of the demo may have changed in later releases. + +::: Backstage integrators control permissions by writing a policy. In general terms, a policy is simply an async function which receives a request to authorize a specific action for a user and (optional) resource, and returns a decision on whether to authorize that permission. Integrators can implement their own policies from scratch, or adopt reusable policies written by others. diff --git a/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md b/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md index f3380bdb6f..aacd60af8c 100644 --- a/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md +++ b/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md @@ -37,7 +37,11 @@ export const todoListPermissions = [todoListCreatePermission]; For this tutorial, we've automatically exported all permissions from this file (see `plugins/todo-list-common/src/index.ts`). -> Note: We use a separate `todo-list-common` package since all permissions authorized by your plugin should be exported from a ["common-library" package](https://backstage.io/docs/local-dev/cli-build-system#package-roles). This allows Backstage integrators to reference them in frontend components as well as permission policies. +:::note Note + +We use a separate `todo-list-common` package since all permissions authorized by your plugin should be exported from a ["common-library" package](https://backstage.io/docs/tooling/cli/build-system#package-roles). This allows Backstage integrators to reference them in frontend components as well as permission policies. + +::: ## Authorizing using the new permission diff --git a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md index 76c1a85e24..b3aeb13a68 100644 --- a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md +++ b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md @@ -144,7 +144,11 @@ export const rules = { isOwner }; `makeCreatePermissionRule` is a helper used to ensure that rules created for this plugin use consistent types for the resource and query. -> Note: To support custom rules defined by Backstage integrators, you must export `createTodoListPermissionRule` from the backend package and provide some way for custom rules to be passed in before the backend starts, likely via `createRouter`. +:::note Note + +To support custom rules defined by Backstage integrators, you must export `createTodoListPermissionRule` from the backend package and provide some way for custom rules to be passed in before the backend starts, likely via `createRouter`. + +::: We have created a new `isOwner` rule, which is going to be automatically used by the permission framework whenever a conditional response is returned in response to an authorized request with an attached `resourceRef`. Specifically, the `apply` function is used to understand whether the passed resource should be authorized or not. diff --git a/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md b/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md index a9e62040c5..84e86140fc 100644 --- a/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md +++ b/docs/permissions/plugin-authors/04-authorizing-access-to-paginated-data.md @@ -36,7 +36,11 @@ This approach will work for simple cases, but it has a downside: it forces us to To avoid this situation, the permissions framework has support for filtering items in the data source itself. In this part of the tutorial, we'll describe the steps required to use that behavior. -> Note: in order to perform authorization filtering in this way, the data source must allow filters to be logically combined with AND, OR, and NOT operators. The conditional decisions returned by the permissions framework use a [nested object](https://backstage.io/docs/reference/plugin-permission-common.permissioncriteria) to combine conditions. If you're implementing a filter API from scratch, we recommend using the same shape for ease of interoperability. If not, you'll need to implement a function which transforms the nested object into your own format. +:::note Note + +In order to perform authorization filtering in this way, the data source must allow filters to be logically combined with AND, OR, and NOT operators. The conditional decisions returned by the permissions framework use a [nested object](https://backstage.io/docs/reference/plugin-permission-common.permissioncriteria) to combine conditions. If you're implementing a filter API from scratch, we recommend using the same shape for ease of interoperability. If not, you'll need to implement a function which transforms the nested object into your own format. + +::: ## Creating the read permission diff --git a/docs/permissions/plugin-authors/05-frontend-authorization.md b/docs/permissions/plugin-authors/05-frontend-authorization.md index 92d855698f..60458aaf4d 100644 --- a/docs/permissions/plugin-authors/05-frontend-authorization.md +++ b/docs/permissions/plugin-authors/05-frontend-authorization.md @@ -8,7 +8,11 @@ In the previous sections, we learned how to protect our plugin's backend API rou Take, for example, the "Add" button in our todo list application. When a user clicks this button, the frontend makes a `POST` request to the `/todos` route of our backend. If a user tries to add a todo but is not authorized, they will have no way of knowing this until they perform the action and are faced with an error. This is a poor user experience. We can do better by disabling the add button. -> Note: Placing frontend components behind authorization cannot take the place of placing your backend routes behind authorization. Authorization checks on the frontend should be used in _addition_ to the corresponding backend authorization, as an improvement to the user experience. If you do not place your backend route behind authorization, a malicious actor can still send a request to the route even if you disabled the corresponding frontend component. +:::note Note + +Placing frontend components behind authorization cannot take the place of placing your backend routes behind authorization. Authorization checks on the frontend should be used in _addition_ to the corresponding backend authorization, as an improvement to the user experience. If you do not place your backend route behind authorization, a malicious actor can still send a request to the route even if you disabled the corresponding frontend component. + +::: ## Using `usePermission` diff --git a/docs/plugins/analytics.md b/docs/plugins/analytics.md index 6b1f0a8254..10a7421057 100644 --- a/docs/plugins/analytics.md +++ b/docs/plugins/analytics.md @@ -46,9 +46,9 @@ To suggest an integration, please [open an issue][add-tool] for the analytics tool your organization uses. Or jump to [Writing Integrations][int-howto] to learn how to contribute the integration yourself! -[ga]: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md -[ga4]: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga4/README.md -[newrelic-browser]: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-newrelic-browser/README.md +[ga]: https://github.com/backstage/community-plugins/blob/main/workspaces/analytics/plugins/analytics-module-ga/README.md +[ga4]: https://github.com/backstage/community-plugins/blob/main/workspaces/analytics/plugins/analytics-module-ga4/README.md +[newrelic-browser]: https://github.com/backstage/community-plugins/blob/main/workspaces/analytics/plugins/analytics-module-newrelic-browser/README.md [qm]: https://github.com/quantummetric/analytics-module-qm/blob/main/README.md [matomo]: https://github.com/janus-idp/backstage-plugins/blob/main/plugins/analytics-module-matomo/README.md [add-tool]: https://github.com/backstage/backstage/issues/new?assignees=&labels=plugin&template=plugin_template.md&title=%5BAnalytics+Module%5D+THE+ANALYTICS+TOOL+TO+INTEGRATE @@ -69,8 +69,7 @@ installed, may be captured. | `discover` | The title of the search result that was clicked on | The `value` is the result rank. A `to` attribute is also provided. | | `not-found` | The path of the resource that resulted in a not found page | Fired by at least TechDocs. | -If there is an event you'd like to see captured, please [open an -issue](https://github.com/backstage/backstage/issues/new?assignees=&labels=enhancement&template=feature_template.md&title=[Analytics%20Event]:%20THE+EVENT+TO+CAPTURE) describing the event you want to see and the questions it +If there is an event you'd like to see captured, please [open an issue](https://github.com/backstage/backstage/issues/new?assignees=&labels=enhancement&template=feature_template.md&title=[Analytics%20Event]:%20THE+EVENT+TO+CAPTURE) describing the event you want to see and the questions it would help you answer. Or jump to [Capturing Events](#capturing-events) to learn how to contribute the instrumentation yourself! diff --git a/docs/plugins/backend-plugin.md b/docs/plugins/backend-plugin.md index 7a51cb635c..255ab4f865 100644 --- a/docs/plugins/backend-plugin.md +++ b/docs/plugins/backend-plugin.md @@ -44,7 +44,11 @@ cd plugins/carmen-backend yarn start ``` -> Note: this documentation assumes you are using the latest version of Backstage and the new backend system. If you are not, please upgrade and migrate your backend using the [Migration Guide](../backend-system/building-backends/08-migrating.md) +:::note Note + +This documentation assumes you are using the latest version of Backstage and the new backend system. If you are not, please upgrade and migrate your backend using the [Migration Guide](../backend-system/building-backends/08-migrating.md) + +::: This will think for a bit, and then say `Listening on :7007`. In a different terminal window, now run diff --git a/docs/plugins/create-a-plugin.md b/docs/plugins/create-a-plugin.md index 481b610e4e..d80e9cd57e 100644 --- a/docs/plugins/create-a-plugin.md +++ b/docs/plugins/create-a-plugin.md @@ -11,7 +11,7 @@ A Backstage Plugin adds functionality to Backstage. To create a new frontend plugin, make sure you've run `yarn install` and installed dependencies, then run the following on your command line (a shortcut to invoking the -[`backstage-cli new --select plugin`](../local-dev/cli-commands.md#new)) +[`backstage-cli new --select plugin`](../tooling/cli/03-commands.md#new)) from the root of your project. ```bash diff --git a/docs/plugins/feature-flags.md b/docs/plugins/feature-flags.md index 7b7a6c1435..3afb8081d5 100644 --- a/docs/plugins/feature-flags.md +++ b/docs/plugins/feature-flags.md @@ -6,39 +6,39 @@ description: Details the process of defining setting and reading a feature flag. Backstage offers the ability to define feature flags inside a plugin or during application creation. This allows you to restrict parts of your plugin to those individual users who have toggled the feature flag to on. -This page describes the process of defining setting and reading a feature flag. If you are looking for using feature flags with software templates that can be found under [Writing Templates](https://backstage.io/docs/features/software-templates/writing-templates#remove-sections-or-fields-based-on-feature-flags). +This page describes the process of defining, setting and reading a feature flag. If you are looking for using feature flags specifically with software templates please see [Writing Templates](https://backstage.io/docs/features/software-templates/writing-templates#remove-sections-or-fields-based-on-feature-flags). ## Defining a Feature Flag ### In a plugin -Defining feature flag in a plugin is done by passing the name of the feature flag into the `featureFlags` array: +Defining a feature flag in a plugin is done by passing the name of the feature flag into the `featureFlags` array: -```ts -/* src/plugin.ts */ -import { createPlugin, createRouteRef } from '@backstage/core-plugin-api'; -import ExampleComponent from './components/ExampleComponent'; +```ts title="src/plugin.ts" +import { createPlugin } from '@backstage/core-plugin-api'; export const examplePlugin = createPlugin({ - id: 'example', - routes: { - root: rootRouteRef, - }, + // ... featureFlags: [{ name: 'show-example-feature' }], + // ... }); ``` ### In the application -Defining feature flag in the application is done by adding feature flags in`featureFlags` array in +Defining a feature flag in the application is done by adding feature flags in `featureFlags` array in the `createApp()` function call: -```ts +```ts title="packages/app/src/App.tsx" +import { createApp } from '@backstage/app-defaults'; + const app = createApp({ // ... featureFlags: [ { - pluginId: '', // pluginId is required for feature flags in plugins. It can be left blank for a feature flag leveraged in the application. + // pluginId is required for feature flags used in plugins. + // pluginId can be left blank for a feature flag used in the application and not in plugins. + pluginId: '', name: 'tech-radar', description: 'Enables the tech radar plugin', }, @@ -49,11 +49,9 @@ const app = createApp({ ## Enabling Feature Flags -Feature flags are defaulted to off and can be updated by individual users in the backstage interface. +Feature flags are defaulted to off and can be updated by individual users in the backstage interface. These are set by navigating to the page under `Settings` > `Feature Flags`. -These are set by navigating to the page under `Settings` > `Feature Flags`. - -The users selection is saved in the users browsers local storage. Once toggled it may be required for a user to refresh the page to see any new changes. +The user's selection is saved in the user's browser local storage. Once a feature flag is toggled it may be required for a user to refresh the page to see the change. ## FeatureFlagged Component @@ -75,7 +73,7 @@ import { FeatureFlagged } from '@backstage/core-app-api'; ## Evaluating Feature Flag State -It is also possible to test the feature flag state using the [FeatureFlags Api](https://backstage.io/docs/reference/core-plugin-api.featureflagsapi). +It is also possible to query a feature flag using the [FeatureFlags Api](https://backstage.io/docs/reference/core-plugin-api.featureflagsapi). ```ts import { useApi, featureFlagsApiRef } from '@backstage/core-plugin-api'; diff --git a/docs/plugins/new-backend-system.md b/docs/plugins/new-backend-system.md index 08ed7e73c7..e8a2ca1b19 100644 --- a/docs/plugins/new-backend-system.md +++ b/docs/plugins/new-backend-system.md @@ -8,7 +8,7 @@ description: Details of the new backend system The new backend system is released and ready for production use, and many plugins and modules have already been migrated. We recommend all plugins and deployments to migrate to the new system. -You can find an example backend setup in [the backend-next package](https://github.com/backstage/backstage/tree/master/packages/backend-next). +You can find an example backend setup in [the backend package](https://github.com/backstage/backstage/tree/master/packages/backend). ## Overview diff --git a/docs/plugins/observability.md b/docs/plugins/observability.md index d8778f07f8..e13653706f 100644 --- a/docs/plugins/observability.md +++ b/docs/plugins/observability.md @@ -15,6 +15,32 @@ See how to install Datadog Events in your app ## Logging +### New Backend + +The backend supplies a central logging service, [`rootLogger`](../backend-system/core-services/root-logger.md), as well as a plugin based logger, [`logger`](../backend-system/core-services/logger.md) from `coreServices`. To add additional granularity to your logs, you can create children from the plugin based logger, using the `.child()` method and provide is with JSON data. For example, if you wanted to log items for a specific span in your plugin, you could do + +```ts +export function createRouter({ logger }) { + const router = Router(); + + router.post('/task/:taskId/queue', (req, res) => { + const { taskId } = req.params; + const taskLogger = logger.child({ task: taskId }); + taskLogger.log('Queueing this task.'); + }); + + router.get('/task/:taskId/results', (req, res) => { + const { taskId } = req.params; + const taskLogger = logger.child({ task: taskId }); + taskLogger.log('Getting the results of this task.'); + }); +} +``` + +You can also add additional metadata to all logs for your Backstage instance by overriding the `rootLogger` implementation, you can see an example in [the `logger` docs](../backend-system/core-services/logger.md#configuring-the-service). + +### Old Backend + The backend supplies a central [winston](https://github.com/winstonjs/winston) root logger that plugins are expected to use for their logging needs. In the default production setup, it emits structured JSON logs on stdout, with a field @@ -37,7 +63,39 @@ An example log line could look as follows: ## Health Checks -The example backend in the Backstage repository +### New Backend + +The new backend is moving towards health checks being plugin-based, as such there is no current plugin for providing a health check route. You can add this yourself easily though, + +```ts +import { + coreServices, + createBackendModule, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; + +const healthCheck = createBackendPlugin({ + pluginId: 'healthcheck', + + register(env) { + env.registerInit({ + deps: { + rootHttpRouter: coreServices.rootHttpRouter, + }, + init: async ({ rootHttpRouter }) => { + // You can adjust the route name and response as you need. + rootHttpRouter.use('/healthcheck', (req, res) => { + res.json({ status: 'ok' }); + }); + }, + }); + }, +}); +``` + +### Old Backend + +The example old backend in the Backstage repository [supplies](https://github.com/backstage/backstage/blob/bc18571b7a742863a770b2a54e785d6bbef7e184/packages/backend/src/index.ts#L99) a very basic health check endpoint on the `/healthcheck` route. You may add such a handler to your backend as well, and supply your own logic to it that fits diff --git a/docs/plugins/proxying.md b/docs/plugins/proxying.md index 40d155e13b..0b64c6eb37 100644 --- a/docs/plugins/proxying.md +++ b/docs/plugins/proxying.md @@ -15,15 +15,20 @@ can be the best choice for communicating with an API. The plugin is already added to a default Backstage project. +### New Backend + +To add it to a project, add the following line in `packages/backend/src/index.ts`: + +```ts +backend.add(import('@backstage/plugin-proxy-backend/alpha')); +``` + +### Old Backend + In `packages/backend/src/index.ts`: ```ts -const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); - -const service = createServiceBuilder(module) - .loadConfig(configReader) - /** ... other routers ... */ - .addRouter('/proxy', await proxy(proxyEnv)); +backend.add(import('@backstage/plugin-proxy-backend/alpha')); ``` ## Configuration @@ -40,6 +45,7 @@ proxy: /simple-example: http://simple.example.com:8080 '/larger-example/v1': target: http://larger.example.com:8080/svc.v1 + credentials: require headers: Authorization: ${EXAMPLE_AUTH_HEADER} # ...or interpolating a value into part of a string, @@ -56,6 +62,23 @@ backend requests to `/api/proxy/simple-example/...` and The value inside each route is either a simple URL string, or an object on the format accepted by [http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware). +Additionally, it has an optional `credentials` key which can have the following +values: + +- `require`: Callers must provide Backstage user or service credentials with + each request. The credentials are not forwarded to the proxy target. This is + the default. +- `forward`: Callers must provide Backstage user or service credentials with + each request, and those credentials are forwarded to the proxy target. +- `dangerously-allow-unauthenticated`: No Backstage credentials are required to + access this proxy target. The target can still apply its own credentials + checks, but the proxy will not help block non-Backstage-blessed callers. If + you also add `allowedHeaders: ['Authorization']` to an endpoint configuration, + then the Backstage token (if provided) WILL be forwarded. + +Note that if you have `backend.auth.dangerouslyDisableDefaultAuthPolicy` set to +`true`, the `credentials` value does not apply; the proxy will behave as if all +endpoints were set to `dangerously-allow-unauthenticated`. If the value is a string, it is assumed to correspond to: @@ -64,6 +87,7 @@ target: changeOrigin: true pathRewrite: '^/': '/' +credentials: require ``` When the target is an object, it is given verbatim to `http-proxy-middleware` @@ -76,6 +100,7 @@ except with the following caveats for convenience: `'^/api/proxy/larger-example/v1/': '/'` is added. That means that a request to `/api/proxy/larger-example/v1/some/path` will be translated to a request to `http://larger.example.com:8080/svc.v1/some/path`. +- If `credentials` is not specified, it is set to `require`. There are also additional settings: diff --git a/docs/plugins/testing.md b/docs/plugins/testing.md index bc212a2581..a97b3d8166 100644 --- a/docs/plugins/testing.md +++ b/docs/plugins/testing.md @@ -369,4 +369,4 @@ Note: wrapping in the test application **requires** you to do a `find()` or ## Debugging Jest Tests -You can find it [here](https://backstage.io/docs/local-dev/cli-build-system#debugging-jest-tests) +You can find it [here](https://backstage.io/docs/tooling/cli/build-system#debugging-jest-tests) diff --git a/docs/publishing.md b/docs/publishing.md index 29853955f1..d7a4f65008 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -52,7 +52,7 @@ Additional steps for the main line release - Create Release Notes PR - Add the release note file as [`/docs/releases/vx.y.0.md`](./releases) - Add an entry to [`/microsite/sidebar.json`](https://github.com/backstage/backstage/blob/master/microsite/sidebars.json) for the release note - - Update the navigation bar item in [`/microsite/docusaurus.config.js`](https://github.com/backstage/backstage/blob/master/microsite/docusaurus.config.js) to point to the new release note + - Update the navigation bar item in [`/microsite/docusaurus.config.ts`](https://github.com/backstage/backstage/blob/master/microsite/docusaurus.config.ts) to point to the new release note - Finally copy the content, without the metadata header, into the description of the [`Version Packages` Pull Request](https://github.com/backstage/backstage/pulls?q=is%3Aopen+is%3Apr+in%3Atitle+%22Version+Packages) Once the release has been published edit the newly created release in the [GitHub repository](https://github.com/backstage/backstage/releases) and replace the text content with the release notes. diff --git a/docs/references/glossary.md b/docs/references/glossary.md index 6db16443e2..906260e710 100644 --- a/docs/references/glossary.md +++ b/docs/references/glossary.md @@ -201,7 +201,7 @@ A service that hosts [packages](#package). The most prominent example is [NPM](h ## Package Role -The declared role of a package, see [package roles](../local-dev/cli-build-system.md#package-roles). +The declared role of a package, see [package roles](../tooling/cli/02-build-system.md#package-roles). ## Permission (core Backstage plugin) diff --git a/docs/releases/v1.12.0-changelog.md b/docs/releases/v1.12.0-changelog.md index df25020aee..49ff79d19a 100644 --- a/docs/releases/v1.12.0-changelog.md +++ b/docs/releases/v1.12.0-changelog.md @@ -60,8 +60,7 @@ This change makes the dependence explicit, and removes the burden on OAuth2-based providers which require an ID token (e.g. this is done by various - default [auth - handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add + default [auth handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add `openid` to their default scopes. _That_ could carry another indirect benefit: by removing `openid` from the default scopes for a provider, grants for resource-specific access tokens can avoid requesting excess ID token-related diff --git a/docs/releases/v1.12.0-next.2-changelog.md b/docs/releases/v1.12.0-next.2-changelog.md index 7a64ec5f84..ed4c5683ba 100644 --- a/docs/releases/v1.12.0-next.2-changelog.md +++ b/docs/releases/v1.12.0-next.2-changelog.md @@ -25,8 +25,7 @@ This change makes the dependence explicit, and removes the burden on OAuth2-based providers which require an ID token (e.g. this is done by various - default [auth - handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add + default [auth handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add `openid` to their default scopes. _That_ could carry another indirect benefit: by removing `openid` from the default scopes for a provider, grants for resource-specific access tokens can avoid requesting excess ID token-related diff --git a/docs/releases/v1.15.0.md b/docs/releases/v1.15.0.md index 336fe7520b..c7ef6b33f9 100644 --- a/docs/releases/v1.15.0.md +++ b/docs/releases/v1.15.0.md @@ -27,8 +27,7 @@ native dependency, and as such needs to be built during `yarn` installation, on the exact architecture that it then executes on. For those who compile and run Backstage on stripped-down environments, you will want to ensure that you have the build basics present, e.g. `build-essential` or similar corresponding to -your operating system of choice. The `isolated-vm` repo has [some further -information](https://github.com/laverdet/isolated-vm#requirements) about the +your operating system of choice. The `isolated-vm` repo has [some further information](https://github.com/laverdet/isolated-vm#requirements) about the build environment requirements. There is a [CVE-2022-39266](https://www.cve.org/CVERecord?id=CVE-2022-39266) @@ -65,8 +64,7 @@ covers of your catalog instance, finding those pesky unprocessed entities that may be stuck in limbo because of an otherwise tricky-to-debug validation issue or similar. -Check out [the plugin’s -README](https://github.com/backstage/backstage/blob/master/plugins/catalog-unprocessed-entities/README.md) +Check out [the plugin’s README](https://github.com/backstage/backstage/blob/master/plugins/catalog-unprocessed-entities/README.md) for details and installation instructions. Contributed by [@alde](https://github.com/alde) in @@ -176,8 +174,7 @@ Contributed by [@sblausten](https://github.com/sblausten) in 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). +[keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). ## Links and References @@ -185,11 +182,9 @@ 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/) + [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) +- 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.15.0-changelog.md) diff --git a/docs/releases/v1.20.0.md b/docs/releases/v1.20.0.md index 921b8219fb..0d0075aa41 100644 --- a/docs/releases/v1.20.0.md +++ b/docs/releases/v1.20.0.md @@ -12,7 +12,7 @@ A huge thanks to the whole team of maintainers and contributors as well as the a ### Support for experimental type build has been removed -The `--experimental-type-build` option is no longer supported by any commands in the Backstage CLI. Existing usage should be migrated to using [subpath exports](https://backstage.io/docs/local-dev/cli-build-system#subpath-exports) instead. +The `--experimental-type-build` option is no longer supported by any commands in the Backstage CLI. Existing usage should be migrated to using [subpath exports](https://backstage.io/docs/tooling/cli/build-system#subpath-exports) instead. ### Experimental support for Vite ⚡ diff --git a/docs/releases/v1.27.0-changelog.md b/docs/releases/v1.27.0-changelog.md new file mode 100644 index 0000000000..28e52caa7b --- /dev/null +++ b/docs/releases/v1.27.0-changelog.md @@ -0,0 +1,1949 @@ +# Release v1.27.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.27.0](https://backstage.github.io/upgrade-helper/?to=1.27.0) + +## @backstage/backend-common@0.22.0 + +### Minor Changes + +- ed83f85: Internal refactor of the database code. + + **BREAKING**: The helper functions `createDatabaseClient` and `ensureDatabaseExists` have been removed from the public interface, since they have no usage within the repository and never were suitable for calling from the outside. Please consider using `coreServices.database` or `DatabaseManager` directly wherever possible instead. + +### Patch Changes + +- 2cc750d: Added `HarnessURLReader` with `readUrl` support. +- 57f692e: Preparing for a stable new backend system release, we are deprecating utilities in the `backend-common` that are not used by the core framework, such as the isomorphic `Git` class. As we will no longer support the isomorphic `Git` utility in the framework packages, we recommend plugins that start maintaining their own implementation of this class. +- 0ec0796: Plugins created through the `legacyPlugin` helper are now able to authenticate requests from plugins that are fully implemented using the new backend system. This fixes the `Key for the ES256 algorithm must be one of type KeyObject or CryptoKey. Received an instance of Uint8Array` error. +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- ccc8851: Added config prop `ensureSchemaExists` to support postgres instances where user can create schemas but not databases. +- f66bbb4: Only create a single actual connection to memcache/redis, even in cases where many `CacheService` instances are made +- ba0b8b4: Added option to `ServerTokenManager.fromConfig` that allows it to be instantiated in production without any configured keys. +- Updated dependencies + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/integration@1.11.0 + +## @backstage/catalog-model@1.5.0 + +### Minor Changes + +- 79025f3: Introduce a domain attribute to the domain entity to allow a hierarchy of domains to exist. + +## @backstage/frontend-app-api@0.7.0 + +### Minor Changes + +- ddddecb: Extensions in app-config now always affect ordering. Previously, only when enabling disabled extensions did they rise to the top. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/integration@1.11.0 + +### Minor Changes + +- 2cc750d: Added `HarnessIntegration` via the `ScmIntegrations` interface. + +## @backstage/repo-tools@0.9.0 + +### Minor Changes + +- 683870a: Adds 2 new commands `repo schema openapi diff` and `package schema openapi diff`. `repo schema openapi diff` is intended to power a new breaking changes check on pull requests and the package level command allows plugin developers to quickly see new API breaking changes. They're intended to be used in complement with the existing `repo schema openapi verify` command to validate your OpenAPI spec against a variety of things. + +### Patch Changes + +- 9ae9bb2: Update the paths logic in the api reports command to support complex subpaths +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + +## @backstage/plugin-catalog@1.20.0 + +### Minor Changes + +- 8834daf: Updated the presentation API to return a promise, in addition to the snapshot and observable that were there before. This makes it much easier to consume the API in a non-React context. + +### Patch Changes + +- 131e5cb: Fix broken links in README. +- 5d99272: Update local development dependencies. +- 4118530: Avoiding pre-loading display total count undefined for table counts +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2 + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/catalog-client@1.6.5 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-search-react@1.7.11 + +## @backstage/plugin-catalog-backend@1.22.0 + +### Minor Changes + +- f2a2a83: Deprecated the `LocationAnalyzer` type, which has been moved to `@backstage/plugin-catalog-node`. +- f2a2a83: The `/alpha` plugin export has had its implementation of the `catalogAnalysisExtensionPoint` updated to reflect the new API. +- 8d14475: Emit well known relationships for the Domain entity kind. + +### Patch Changes + +- 131e5cb: Fix broken links in README. +- c6cb568: Add lifecycle monitoring for the catalog processing +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- 8479a0b: Fixed bug in stitching queue gauge that included entities that are scheduled in the future. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-search-backend-module-catalog@0.1.24 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-events-node@0.3.4 + - @backstage/integration@1.11.0 + - @backstage/backend-openapi-utils@0.1.11 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/plugin-catalog-import@0.11.0 + +### Minor Changes + +- e1174b0: `EntityListComponent` uses `entityPresentationApi` instead of `humanizeEntityRef` to display Entity + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/integration@1.11.0 + - @backstage/catalog-client@1.6.5 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-node@1.12.0 + +### Minor Changes + +- f2a2a83: Added `LocationAnalyzer` type, moved from `@backstage/plugin-catalog-backend`. +- f2a2a83: Breaking change to `/alpha` API where the `catalogAnalysisExtensionPoint` has been reworked. The `addLocationAnalyzer` method has been renamed to `addScmLocationAnalyzer`, and a new `setLocationAnalyzer` method has been added which allows the full `LocationAnalyzer` implementation to be overridden. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/plugin-catalog-react@1.12.0 + +### Minor Changes + +- 8834daf: Updated the presentation API to return a promise, in addition to the snapshot and observable that were there before. This makes it much easier to consume the API in a non-React context. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/catalog-client@1.6.5 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-scaffolder@1.20.0 + +### Minor Changes + +- 4268696: `MultiEntityPicker` uses `EntityDisplayName` instead of `humanizeEntityRef` to display entity. + +### Patch Changes + +- 9156654: Capturing more event clicks for scaffolder +- 131e5cb: Fix broken links in README. +- 0040ec2: Updated dependency `@rjsf/utils` to `5.18.2`. + Updated dependency `@rjsf/core` to `5.18.2`. + Updated dependency `@rjsf/material-ui` to `5.18.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.2`. +- 762141c: Fixed a bug where the `MultiEntityPicker` was not able to be set as required +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2 + - @backstage/plugin-scaffolder-react@1.8.5 + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/integration@1.11.0 + - @backstage/catalog-client@1.6.5 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0 + +### Minor Changes + +- 18f736f: Add examples for `gitlab:projectVariable:create` scaffolder action & improve related tests + +### Patch Changes + +- 8fa8a00: Add merge method and squash option for project creation +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- ffc73ec: Add examples for `gitlab:repo:push` scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/app-defaults@1.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + +## @backstage/backend-app-api@0.7.3 + +### Patch Changes + +- 4cd5ff0: Add ability to configure the Node.js HTTP Server when configuring the root HTTP Router service + +- e8199b1: Move the JWKS registration outside of the lifecycle middleware + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. + +- dc8c5dd: The default `TokenManager` implementation no longer requires keys to be configured in production, but it will throw an errors when generating or authenticating tokens. The default `AuthService` implementation will now also provide additional context if such an error is throw when falling back to using the `TokenManager` service to generate tokens for outgoing requests. + +- 025641b: Redact `meta` fields too with the logger + +- 09f8988: Remove explicit `alg` check for user tokens in `verifyToken` + +- 5863e02: Internal refactor to only create one external token handler + +- a1dc547: Added support for camel case CSP directives in app-config. For example: + + ```yaml + backend: + csp: + upgradeInsecureRequests: false + ``` + +- 329cc34: Added logging of all plugins being initialized, periodic status, and completion. + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/backend-defaults@0.2.18 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/backend-dynamic-feature-service@0.2.10 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- b611fd0: Updates the `scanRoot` method in the `PluginScanner` class to specifically ignore the `lost+found` directory, which is a system-generated directory used for file recovery on Unix-like systems. Skipping this directory avoids unnecessary errors. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-app-node@0.1.18 + - @backstage/plugin-events-backend@0.3.5 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/backend-openapi-utils@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + +## @backstage/backend-plugin-api@0.6.18 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- 1fedf0c: Removed explicit `toString()` method from `ServiceRef` type. +- Updated dependencies + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/backend-tasks@0.5.23 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + +## @backstage/backend-test-utils@0.3.8 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/catalog-client@1.6.5 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + +## @backstage/cli@0.26.5 + +### Patch Changes + +- b8f1fc2: The `build-workspace` command no longer manually runs `yarn postpack`, relying instead on the fact that running `yarn pack` will automatically invoke the `postpack` script. No action is necessary if you are running the latest version of yarn 1, 3, or 4. +- fcd3462: Both the target and types library have been bumped from ES2021 to ES2022 in `@backstage/cli/config/tsconfig.json`. +- 0cc5ed3: Add support for `versions:migrate` to do code changes. Can be skipped with `--no-code-changes` +- f97ad04: Add preserveModules to rollup, which allows better async loading and tree-shaking in webpack +- 2a6f10d: The `versions:bump` command will no longer exit with a non-zero status if the version bump fails due to forbidden duplicate package installations. It will now also provide more information about how to troubleshoot such an error. The set of forbidden duplicates has also been expanded to include all `@backstage/*-app-api` packages. +- c5d7b40: Allow passing a `--require` argument through to the Node process during `package start` +- cc3c518: Fixed an issue causing the `repo fix` command to set an incorrect `workspace` property using Windows +- 812dff0: Add previously-missing semicolon in file templated by `backstage-cli new --select plugin`. +- f185603: Fixed the dynamic import of vite. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.11.0 + +## @backstage/core-app-api@1.12.5 + +### Patch Changes + +- 1bed9a3: The Backstage identity session expiration check will no longer fall back to using the provider expiration. This was introduced to smooth out the rollout of Backstage release 1.18, and is no longer needed. + +## @backstage/core-compat-api@0.2.5 + +### Patch Changes + +- 5d99272: Update local development dependencies. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/core-components@0.14.7 + +### Patch Changes + +- e42779e: Properly log the `errorInfo` in `ErrorBoundary` +- 5223c4c: Fixed an internal circular import that broke Jest mocks. +- 71e4229: Added optional `initialShowDropDown` prop to `SidebarSubmenuItem` to internally manage the initial display state of the dropdown items. +- a2ee4df: Add `alignGauge` prop to the `GaugeCard`, and a small size version. When `alignGauge` is `'bottom'` the gauge will vertically align the gauge in the cards, even when the card titles span across multiple lines. + Add `alignContent` prop to the `InfoCard`, defaulting to `'normal'` with the option of `'bottom'` which vertically aligns the content to the bottom of the card. +- 5b7b49b: The `SignInPage` guest provider will now fall back to legacy guest auth if the backend request fails, allowing guest auth without a running backend. +- 359376a: Removing react-text-truncate with css styles. +- Updated dependencies + - @backstage/theme@0.5.4 + +## @backstage/create-app@0.5.15 + +### Patch Changes + +- c066c88: Removed `packages/backend/src/types.ts` from the template as it is unused. It was mistakenly left in after moving the template to the new backend system. +- 5d99272: Update local development dependencies. +- 0478509: Bumped create-app version. +- d85dd88: Bumped create-app version. +- 8105aad: Removed the Tech Radar and GitHub Actions plugins from the template, which have been moved to the community plugins repository. + +## @backstage/dev-utils@1.0.32 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/app-defaults@1.5.5 + - @backstage/integration-react@1.1.27 + +## @backstage/eslint-plugin@0.1.8 + +### Patch Changes + +- 65ec043: add some `pickers` fixes + +## @backstage/frontend-plugin-api@0.6.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + +## @backstage/frontend-test-utils@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.0 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/test-utils@1.5.5 + +## @backstage/integration-react@1.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.11.0 + +## @techdocs/cli@1.8.11 + +### Patch Changes + +- 1a0e009: Fix cookie endpoint mock for `serve` +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-techdocs-node@1.12.4 + +## @backstage/test-utils@1.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + +## @backstage/theme@0.5.4 + +### Patch Changes + +- f1462df: Fixed bug where scrollbars don't pick up the theme when in dark mode + +## @backstage/plugin-api-docs@0.11.5 + +### Patch Changes + +- 5d99272: Update local development dependencies. +- 725ff0b: Fix dark mode text color inside tables in `description:` from OpenAPI definitions +- Updated dependencies + - @backstage/plugin-catalog@1.20.0 + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-app-backend@0.3.66 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-app-node@0.1.18 + +## @backstage/plugin-app-node@0.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + +## @backstage/plugin-app-visualizer@0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/plugin-auth-backend@0.22.5 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- 4a0577e: fix: Move config declarations to appropriate auth backend modules +- ea9262b: Allow overriding default ownership resolving with the new `AuthOwnershipResolutionExtensionPoint` +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.10 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15 + - @backstage/plugin-auth-backend-module-oidc-provider@0.1.9 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.10 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.1 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.1 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.13 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.15 + - @backstage/plugin-auth-backend-module-google-provider@0.1.15 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.13 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.15 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.11 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.11 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.10 + +### Patch Changes + +- 4a0577e: fix: Move config declarations to appropriate auth backend modules +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-backend@0.22.5 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.15 + +### Patch Changes + +- 4a0577e: fix: Move config declarations to appropriate auth backend modules +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.4 + +### Patch Changes + +- 07d8cca: Error if used outside of a development environment without explicit allowance +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.1.9 + +### Patch Changes + +- dd53bf3: Add nonce to authorize request to be added in ID token +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-backend@0.22.5 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-auth-node@0.4.13 + +### Patch Changes + +- ea9262b: Allow overriding default ownership resolving with the new `AuthOwnershipResolutionExtensionPoint` +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/catalog-client@1.6.5 + +## @backstage/plugin-auth-react@0.1.2 + +### Patch Changes + +- c297afd: When using `CookieAuthRefreshProvider` or `useCookieAuthRefresh`, a 404 response from the cookie endpoint will now be treated as if cookie auth is disabled and is not needed. +- Updated dependencies + - @backstage/core-components@0.14.7 + +## @backstage/plugin-bitbucket-cloud-common@0.2.19 + +### Patch Changes + +- d76cb29: Updated dependency `ts-morph` to `^22.0.0`. +- Updated dependencies + - @backstage/integration@1.11.0 + +## @backstage/plugin-catalog-backend-module-aws@0.3.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/integration@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-catalog-backend-module-azure@0.1.38 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/integration@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1 + +### Patch Changes + +- f3f0281: Fix incorrect dependency import. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/backend-openapi-utils@0.1.11 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.19 + - @backstage/integration@1.11.0 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.32 + +### Patch Changes + +- 062ffb1: Allow skipping archived repositories (`skipArchivedRepos` flag) on Bitbucket. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/integration@1.11.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.35 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/integration@1.11.0 + +## @backstage/plugin-catalog-backend-module-github@0.6.1 + +### Patch Changes + +- 0b50143: GitHub push events now schedule a refresh on entities that have a `refresh_key` matching the `catalogPath` config itself. + This allows to support a `catalogPath` configuration that uses glob patterns. + +- f2a2a83: Updated to use the new `catalogAnalysisExtensionPoint` API. + +- 5bdeaa7: Added `alwaysUseDefaultNamespace` option to `GithubMultiOrgEntityProvider`. + + If set to true, the provider will use `default` as the namespace for all group entities. Groups with the same name across different orgs will be considered the same group. + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-events-node@0.3.4 + - @backstage/integration@1.11.0 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.13 + +### Patch Changes + +- 5bdeaa7: Fixed an issue where the `catalog-backend-module-github-org` would not correctly create groups using `default` as namespace in case a single organization was configured. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-catalog-backend-module-github@0.6.1 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.15 + +### Patch Changes + +- a70377d: Added events support for `GitlabDiscoveryEntityProvider` and `GitlabOrgDiscoveryEntityProvider`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-events-node@0.3.4 + - @backstage/integration@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.1 + +### Patch Changes + +- a70377d: Added a new `catalog-backend-module-gitlab-org` module which adds the `GitlabOrgDiscoveryEntityProvider` to the catalog's providers using the new backend system. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.15 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.23 + +### Patch Changes + +- 8c1ab9e: Fix plugin/incremental-ingestion 'Maximum call stack size exceeded' error when ingest large entities. +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.34 + +### Patch Changes + +- 7699967: Remove dependency to Winston Logger and use Backstage LoggerService instead +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.26 + +### Patch Changes + +- 49eab29: Fixed disabling of user photo fetching. Previously, the config value wasn't propagated properly, so user photos was still being fetched despite disabled by config. +- 6e370e6: Handle fetching huge amounts of users from Azure without crashing +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.36 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/integration@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2 + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.5 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- 6f5a3a3: Correctly convert owner to string in case owner has not been provided +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-catalog-common@1.0.23 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-graph@0.4.5 + +### Patch Changes + +- 39564b3: Allow multiple edges with different type (e.g. `ownedBy` and `applicationOwnerBy`) to have the same source and target node. +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/catalog-client@1.6.5 + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-config-schema@0.1.55 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + +## @backstage/plugin-devtools@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/plugin-devtools-backend@0.3.4 + +### Patch Changes + +- 036feca: Added discovery property to the readme documentation to ensure that it will build when setting it up as new to a Backstage instance +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/plugin-events-backend@0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-backend-module-azure@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-backend-module-gerrit@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-backend-module-github@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-backend-module-gitlab@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-backend-test-utils@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.4 + +## @backstage/plugin-events-node@0.3.4 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + +## @backstage/plugin-home@0.7.4 + +### Patch Changes + +- 2196d3e: Use relative time when displaying visits from the same day +- 0040ec2: Updated dependency `@rjsf/utils` to `5.18.2`. + Updated dependency `@rjsf/core` to `5.18.2`. + Updated dependency `@rjsf/material-ui` to `5.18.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.2`. +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/plugin-home-react@0.1.13 + - @backstage/core-app-api@1.12.5 + - @backstage/catalog-client@1.6.5 + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/plugin-home-react@0.1.13 + +### Patch Changes + +- 0040ec2: Updated dependency `@rjsf/utils` to `5.18.2`. + Updated dependency `@rjsf/core` to `5.18.2`. + Updated dependency `@rjsf/material-ui` to `5.18.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.2`. +- Updated dependencies + - @backstage/core-components@0.14.7 + +## @backstage/plugin-kubernetes@0.11.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/plugin-kubernetes-react@0.3.5 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-kubernetes-backend@0.17.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-kubernetes-common@0.7.6 + - @backstage/plugin-kubernetes-node@0.1.12 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/plugin-kubernetes-cluster@0.0.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/plugin-kubernetes-react@0.3.5 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-kubernetes-common@0.7.6 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-kubernetes-node@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-kubernetes-react@0.3.5 + +### Patch Changes + +- 3102a99: add the namespace label to CronJobDrawer & IngressDrawer. +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-notifications@0.2.1 + +### Patch Changes + +- e6bf85f: Allow overriding `NotificationsPage` page properties +- f730c0b: The user can newly mark all unread messages as read at one click. +- bfcb2f1: Allow showing notifications as snackbars in the UI +- e49a810: Show all notifications by default to match the sidebar item status +- 42eaf63: Increase default and allow modifying notification snackbar auto hide duration +- a42a19b: Empty descriptions are not rendered to improve the look&feel. +- 1bc3b86: Fix to show web notifications even when browser is on foreground. Fix duplicate notifications with multiple tabs. +- f793112: Allow defining `className` and additional properties for `NotificationsSideBarItem` +- e1c7d6e: Fix infinite loop in the notification title counter +- fcda449: The rendered size of a notification is limited for very long descriptions. +- f6633ca: Add option to set the notification as read automatically when the notification link is opened +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/theme@0.5.4 + +## @backstage/plugin-notifications-backend@0.2.1 + +### Patch Changes + +- d541ff6: Fixed email processor `esm` issue and config reading +- 295c05d: Support for filtering entities from notification recipients after resolving them from the recipients +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- cba628a: Add possibility to generate random notifications on the fly in local development +- ee09dfc: Updated documentation for sending messages by external services. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-notifications-node@0.1.4 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-signals-node@0.1.4 + +## @backstage/plugin-notifications-backend-module-email@0.0.1 + +### Patch Changes + +- d541ff6: Fixed email processor `esm` issue and config reading +- e538b10: Support relative links in notifications sent via email +- dbf2696: Allow sending notifications by email with the new notifications module +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-notifications-node@0.1.4 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/catalog-client@1.6.5 + +## @backstage/plugin-notifications-node@0.1.4 + +### Patch Changes + +- 295c05d: Support for filtering entities from notification recipients after resolving them from the recipients +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-signals-node@0.1.4 + +## @backstage/plugin-org@0.6.25 + +### Patch Changes + +- 99e6105: Fix ownership card sometimes locking up for complex org structures +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-org-react@0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/catalog-client@1.6.5 + +## @backstage/plugin-permission-backend@0.5.42 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/plugin-permission-node@0.7.29 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-proxy-backend@0.4.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + +## @backstage/plugin-scaffolder-backend@1.22.6 + +### Patch Changes + +- 131e5cb: Fix broken links in README. +- 025641b: Fix issue with the log format not being respected when logging from actions +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- e4b50ab: Scaffolder workspace serialization +- 025641b: Redact `meta` fields too with the logger +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2 + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.8 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.8 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/integration@1.11.0 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16 + - @backstage/plugin-permission-node@0.7.29 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.10 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.10 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8 + - @backstage/integration@1.11.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8 + +### Patch Changes + +- 24dd655: Add examples for `publish:bitbucketServer:pull-request` scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.42 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.8 + +### Patch Changes + +- 554af73: Allow defining `repoVisibility` field for the action `publish:gitea` +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.2.8 + +### Patch Changes + +- 5d99272: Update local development dependencies. +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- 52ab241: Adding support to change the default commit author for `publish:github:pull-request` +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.1 + +### Patch Changes + +- 503d769: Add a new scaffolder action to allow sending notifications from templates +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/plugin-notifications-node@0.1.4 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.35 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/plugin-scaffolder-node-test-utils@0.1.4 + +## @backstage/plugin-scaffolder-common@1.5.2 + +### Patch Changes + +- 9156654: Capturing more event clicks for scaffolder +- Updated dependencies + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-scaffolder-node@0.4.4 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- e4b50ab: Scaffolder workspace serialization +- f633efa: To remove the dependency on the soon-to-be-deprecated `backend-common` package, this package now maintains its own isomorphic Git class implementation. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-test-utils@0.3.8 + - @backstage/plugin-scaffolder-node@0.4.4 + +## @backstage/plugin-scaffolder-react@1.8.5 + +### Patch Changes + +- 9156654: Capturing more event clicks for scaffolder +- 0040ec2: Updated dependency `@rjsf/utils` to `5.18.2`. + Updated dependency `@rjsf/core` to `5.18.2`. + Updated dependency `@rjsf/material-ui` to `5.18.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.2`. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/catalog-client@1.6.5 + +## @backstage/plugin-search@1.4.11 + +### Patch Changes + +- 0501243: Added `aria-label` attribute to DialogTitle element and set `aria-modal` attribute to `true` for improved accessibility in the search modal. +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/plugin-search-react@1.7.11 + +## @backstage/plugin-search-backend@1.5.8 + +### Patch Changes + +- c6cb568: Add lifecycle monitoring for the search index registry +- Updated dependencies + - @backstage/repo-tools@0.9.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/backend-openapi-utils@0.1.11 + - @backstage/plugin-permission-node@0.7.29 + +## @backstage/plugin-search-backend-module-catalog@0.1.24 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- d5fff66: Fix wiring of the module exported at the `/alpha` path, which was causing authentication failures. +- 5dc5f4f: Allow the `tokenManager` parameter to be optional when instantiating collator +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-search-backend-module-elasticsearch@1.4.1 + +### Patch Changes + +- 5252ee1: Fix never resolved indexer promise. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-search-backend-node@1.2.22 + +## @backstage/plugin-search-backend-module-explore@0.1.24 + +### Patch Changes + +- ca6e2e0: Migrate search collator to use the new auth services. +- 5d99272: Update README.md to point to explore plugin in community-plugins repository. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-search-backend-node@1.2.22 + +## @backstage/plugin-search-backend-module-pg@0.5.27 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-search-backend-node@1.2.22 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-search-backend-node@1.2.22 + +## @backstage/plugin-search-backend-module-techdocs@0.1.23 + +### Patch Changes + +- 5dc5f4f: Allow the `tokenManager` parameter to be optional when instantiating collator +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-techdocs-node@1.12.4 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-search-backend-node@1.2.22 + +### Patch Changes + +- c6cb568: Add lifecycle monitoring for the search index registry +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + +## @backstage/plugin-search-react@1.7.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/theme@0.5.4 + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/plugin-signals@0.0.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/theme@0.5.4 + +## @backstage/plugin-signals-backend@0.1.4 + +### Patch Changes + +- 845d56a: Improved signal lifecycle management and added server side pinging of connections +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-signals-node@0.1.4 + +## @backstage/plugin-signals-node@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-auth-node@0.4.13 + +## @backstage/plugin-techdocs@1.10.5 + +### Patch Changes + +- d2cc139: Update path in Readme for Plugin Techdocs to show the correct setup information. +- 5863cf7: The `techdocs.builder` config is now optional and it will default to `local`. +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-react@0.1.2 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/integration@1.11.0 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-search-react@1.7.11 + - @backstage/plugin-techdocs-react@1.2.4 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.32 + +### Patch Changes + +- 2f13862: Fix bug in TechDocsAddonTester when jest.resetAllMocks is called between tests +- Updated dependencies + - @backstage/plugin-catalog@1.20.0 + - @backstage/plugin-techdocs@1.10.5 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/core-app-api@1.12.5 + - @backstage/integration-react@1.1.27 + - @backstage/test-utils@1.5.5 + - @backstage/plugin-search-react@1.7.11 + - @backstage/plugin-techdocs-react@1.2.4 + +## @backstage/plugin-techdocs-backend@1.10.5 + +### Patch Changes + +- 5863cf7: The `techdocs.builder` config is now optional and it will default to `local`. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-techdocs-node@1.12.4 + - @backstage/integration@1.11.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.23 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/integration@1.11.0 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-techdocs-react@1.2.4 + +## @backstage/plugin-techdocs-node@1.12.4 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/integration@1.11.0 + +## @backstage/plugin-techdocs-react@1.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-user-settings@0.8.6 + +### Patch Changes + +- 131e5cb: Fix broken links in README. +- Updated dependencies + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/frontend-plugin-api@0.6.5 + +## @backstage/plugin-user-settings-backend@0.2.17 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + +## example-app@0.2.97 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5 + - @backstage/plugin-scaffolder@1.20.0 + - @backstage/plugin-user-settings@0.8.6 + - @backstage/plugin-catalog@1.20.0 + - @backstage/plugin-notifications@0.2.1 + - @backstage/plugin-api-docs@0.11.5 + - @backstage/plugin-home@0.7.4 + - @backstage/cli@0.26.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-techdocs@1.10.5 + - @backstage/plugin-catalog-import@0.11.0 + - @backstage/frontend-app-api@0.7.0 + - @backstage/plugin-auth-react@0.1.2 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/plugin-catalog-graph@0.4.5 + - @backstage/plugin-search@1.4.11 + - @backstage/plugin-org@0.6.25 + - @backstage/app-defaults@1.5.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4 + - @backstage/plugin-devtools@0.1.14 + - @backstage/plugin-kubernetes@0.11.10 + - @backstage/plugin-kubernetes-cluster@0.0.11 + - @backstage/plugin-search-react@1.7.11 + - @backstage/plugin-signals@0.0.6 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10 + - @backstage/plugin-techdocs-react@1.2.4 + +## example-app-next@0.0.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5 + - @backstage/plugin-scaffolder@1.20.0 + - @backstage/plugin-user-settings@0.8.6 + - @backstage/plugin-catalog@1.20.0 + - @backstage/plugin-notifications@0.2.1 + - @backstage/core-compat-api@0.2.5 + - @backstage/plugin-api-docs@0.11.5 + - @backstage/plugin-home@0.7.4 + - @backstage/cli@0.26.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-techdocs@1.10.5 + - @backstage/plugin-catalog-import@0.11.0 + - @backstage/frontend-app-api@0.7.0 + - @backstage/plugin-auth-react@0.1.2 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/plugin-catalog-graph@0.4.5 + - @backstage/plugin-search@1.4.11 + - @backstage/plugin-org@0.6.25 + - @backstage/app-defaults@1.5.5 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-app-visualizer@0.1.6 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4 + - @backstage/plugin-kubernetes@0.11.10 + - @backstage/plugin-kubernetes-cluster@0.0.11 + - @backstage/plugin-search-react@1.7.11 + - @backstage/plugin-signals@0.0.6 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10 + - @backstage/plugin-techdocs-react@1.2.4 + +## app-next-example-plugin@0.0.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/frontend-plugin-api@0.6.5 + +## example-backend@0.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.22.6 + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.8 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5 + - @backstage/plugin-search-backend-module-catalog@0.1.24 + - @backstage/plugin-notifications-backend@0.2.1 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-backend@0.22.5 + - @backstage/plugin-app-backend@0.3.66 + - @backstage/plugin-devtools-backend@0.3.4 + - @backstage/plugin-signals-backend@0.1.4 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/plugin-search-backend@1.5.8 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15 + - @backstage/plugin-techdocs-backend@1.10.5 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.4 + - @backstage/backend-defaults@0.2.18 + - @backstage/plugin-search-backend-module-explore@0.1.24 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-search-backend-module-techdocs@0.1.23 + - @backstage/plugin-catalog-backend-module-openapi@0.1.36 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16 + - @backstage/plugin-kubernetes-backend@0.17.1 + - @backstage/plugin-permission-backend@0.5.42 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15 + - @backstage/plugin-permission-node@0.7.29 + - @backstage/plugin-proxy-backend@0.4.16 + +## example-backend-legacy@0.2.98 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.4.1 + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-scaffolder-backend@1.22.6 + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5 + - @backstage/plugin-search-backend-module-catalog@0.1.24 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-search-backend-module-pg@0.5.27 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-backend@0.22.5 + - @backstage/plugin-app-backend@0.3.66 + - @backstage/plugin-devtools-backend@0.3.4 + - @backstage/plugin-signals-backend@0.1.4 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/plugin-search-backend@1.5.8 + - @backstage/plugin-techdocs-backend@1.10.5 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-search-backend-module-explore@0.1.24 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/integration@1.11.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.23 + - example-app@0.2.97 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16 + - @backstage/plugin-events-backend@0.3.5 + - @backstage/plugin-kubernetes-backend@0.17.1 + - @backstage/plugin-permission-backend@0.5.42 + - @backstage/plugin-permission-node@0.7.29 + - @backstage/plugin-proxy-backend@0.4.16 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.35 + - @backstage/plugin-signals-node@0.1.4 + +## e2e-test@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.15 + +## techdocs-cli-embedded-app@0.2.96 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.20.0 + - @backstage/cli@0.26.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-techdocs@1.10.5 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/app-defaults@1.5.5 + - @backstage/integration-react@1.1.27 + - @backstage/test-utils@1.5.5 + - @backstage/plugin-techdocs-react@1.2.4 + +## @internal/plugin-todo-list@1.0.27 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + +## @internal/plugin-todo-list-backend@1.0.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 diff --git a/docs/releases/v1.27.0-next.1-changelog.md b/docs/releases/v1.27.0-next.1-changelog.md new file mode 100644 index 0000000000..77c6919cda --- /dev/null +++ b/docs/releases/v1.27.0-next.1-changelog.md @@ -0,0 +1,1487 @@ +# Release v1.27.0-next.1 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.27.0-next.1](https://backstage.github.io/upgrade-helper/?to=1.27.0-next.1) + +## @backstage/backend-common@0.22.0-next.1 + +### Minor Changes + +- ed83f85: Internal refactor of the database code. + + **BREAKING**: The helper functions `createDatabaseClient` and `ensureDatabaseExists` have been removed from the public interface, since they have no usage within the repository and never were suitable for calling from the outside. Please consider using `coreServices.database` or `DatabaseManager` directly wherever possible instead. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/app-defaults@1.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/backend-app-api@0.7.2-next.1 + +### Patch Changes + +- 09f8988: Remove explicit `alg` check for user tokens in `verifyToken` +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/cli-node@0.2.5 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/backend-defaults@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + +## @backstage/backend-dynamic-feature-service@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-events-backend@0.3.5-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/cli-node@0.2.5 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/plugin-app-node@0.1.18-next.1 + +## @backstage/backend-openapi-utils@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/backend-plugin-api@0.6.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + +## @backstage/backend-tasks@0.5.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/backend-test-utils@0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/core-compat-api@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/core-components@0.14.6-next.1 + +### Patch Changes + +- 5223c4c: Fixed an internal circular import that broke Jest mocks. +- 5b7b49b: The `SignInPage` guest provider will now fall back to legacy guest auth if the backend request fails, allowing guest auth without a running backend. + +## @backstage/create-app@0.5.15-next.1 + +### Patch Changes + +- Bumped create-app version. + +## @backstage/dev-utils@1.0.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/integration-react@1.1.26 + +## @backstage/frontend-app-api@0.6.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/frontend-plugin-api@0.6.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/frontend-test-utils@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.6.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/repo-tools@0.8.1-next.1 + +### Patch Changes + +- 9ae9bb2: Update the paths logic in the api reports command to support complex subpaths +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/cli-node@0.2.5 + - @backstage/config-loader@1.8.0 + +## @techdocs/cli@1.8.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-techdocs-node@1.12.4-next.1 + +## @backstage/plugin-api-docs@0.11.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-app-backend@0.3.66-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/plugin-app-node@0.1.18-next.1 + +## @backstage/plugin-app-node@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-app-visualizer@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-auth-backend@0.22.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.10-next.1 + - @backstage/plugin-auth-backend-module-oidc-provider@0.1.9-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.10-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.1-next.1 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.1-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.15-next.1 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.13-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.15-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.11-next.1 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.1-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.13-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.15-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.11-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-backend@0.22.5-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-backend@0.22.5-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-node@0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-auth-react@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-catalog@1.19.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2-next.1 + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-catalog-backend@1.22.0-next.1 + +### Patch Changes + +- 8479a0b: Fixed bug in stitching queue gauge that included entities that are scheduled in the future. +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/backend-openapi-utils@0.1.11-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/backend-openapi-utils@0.1.11-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-backend-module-github@0.6.1-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.15-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.15-next.3 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.26-next.1 + +### Patch Changes + +- 49eab29: Fixed disabling of user photo fetching. Previously, the config value wasn't propagated properly, so user photos was still being fetched despite disabled by config. +- 6e370e6: Handle fetching huge amounts of users from Azure without crashing +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.1 + +### Patch Changes + +- 6f5a3a3: Correctly convert owner to string in case owner has not been provided +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-graph@0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-catalog-import@0.10.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-catalog-node@1.11.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-catalog-react@1.11.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-config-schema@0.1.55-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-devtools@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-devtools-backend@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend-module-azure@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend-module-github@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.4-next.1 + +## @backstage/plugin-events-node@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-home@0.7.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-home-react@0.1.13-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-home-react@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-kubernetes@0.11.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-kubernetes-react@0.3.5-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + +## @backstage/plugin-kubernetes-backend@0.17.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-kubernetes-node@0.1.12-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-kubernetes-cluster@0.0.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-kubernetes-react@0.3.5-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + +## @backstage/plugin-kubernetes-node@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-kubernetes-react@0.3.5-next.1 + +### Patch Changes + +- 3102a99: add the namespace label to CronJobDrawer & IngressDrawer. +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-notifications@0.2.1-next.1 + +### Patch Changes + +- f730c0b: The user can newly mark all unread messages as read at one click. +- bfcb2f1: Allow showing notifications as snackbars in the UI +- f6633ca: Add option to set the notification as read automatically when the notification link is opened +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-notifications-backend@0.2.1-next.1 + +### Patch Changes + +- 295c05d: Support for filtering entities from notification recipients after resolving them from the recipients +- cba628a: Add possibility to generate random notifications on the fly in local development +- Updated dependencies + - @backstage/plugin-notifications-node@0.1.4-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-signals-node@0.1.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-notifications-backend-module-email@0.0.1-next.0 + +### Patch Changes + +- dbf2696: Allow sending notifications by email with the new notifications module +- Updated dependencies + - @backstage/plugin-notifications-node@0.1.4-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-notifications-node@0.1.4-next.1 + +### Patch Changes + +- 295c05d: Support for filtering entities from notification recipients after resolving them from the recipients +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-signals-node@0.1.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-org@0.6.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-org-react@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + +## @backstage/plugin-permission-backend@0.5.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-permission-node@0.7.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-proxy-backend@0.4.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder@1.19.4-next.1 + +### Patch Changes + +- 9156654: Capturing more event clicks for scaffolder +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2-next.1 + - @backstage/plugin-scaffolder-react@1.8.5-next.1 + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-scaffolder-backend@1.22.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.4-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.10-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.8-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.10-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.8-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/plugin-scaffolder-node-test-utils@0.1.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-common@1.5.2-next.1 + +### Patch Changes + +- 9156654: Capturing more event clicks for scaffolder + +## @backstage/plugin-scaffolder-node@0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-test-utils@0.3.8-next.1 + +## @backstage/plugin-scaffolder-react@1.8.5-next.1 + +### Patch Changes + +- 9156654: Capturing more event clicks for scaffolder +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.2-next.1 + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + +## @backstage/plugin-search@1.4.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-search-backend@1.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/repo-tools@0.8.1-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/backend-openapi-utils@0.1.11-next.1 + +## @backstage/plugin-search-backend-module-catalog@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-search-backend-module-elasticsearch@1.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-search-backend-module-explore@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-search-backend-module-pg@0.5.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-search-backend-module-techdocs@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/plugin-techdocs-node@1.12.4-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-search-backend-node@1.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-search-react@1.7.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-signals@0.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-signals-backend@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-signals-node@0.1.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-signals-node@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-techdocs@1.10.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-auth-react@0.1.2-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-techdocs@1.10.5-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + +## @backstage/plugin-techdocs-backend@1.10.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.1 + - @backstage/plugin-techdocs-node@1.12.4-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + +## @backstage/plugin-techdocs-node@1.12.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/plugin-techdocs-react@1.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @backstage/plugin-user-settings@0.8.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## @backstage/plugin-user-settings-backend@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## example-app@0.2.97-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5-next.1 + - @backstage/plugin-scaffolder@1.19.4-next.1 + - @backstage/plugin-notifications@0.2.1-next.1 + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/cli@0.26.5-next.0 + - @backstage/frontend-app-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-api-docs@0.11.5-next.1 + - @backstage/plugin-auth-react@0.1.2-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.1 + - @backstage/plugin-catalog-import@0.10.11-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4-next.1 + - @backstage/plugin-devtools@0.1.14-next.1 + - @backstage/plugin-home@0.7.4-next.1 + - @backstage/plugin-kubernetes@0.11.10-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.1 + - @backstage/plugin-org@0.6.25-next.1 + - @backstage/plugin-search@1.4.11-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-signals@0.0.6-next.1 + - @backstage/plugin-techdocs@1.10.5-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + - @backstage/plugin-user-settings@0.8.6-next.1 + +## example-app-next@0.0.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5-next.1 + - @backstage/plugin-scaffolder@1.19.4-next.1 + - @backstage/plugin-notifications@0.2.1-next.1 + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/cli@0.26.5-next.0 + - @backstage/frontend-app-api@0.6.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-api-docs@0.11.5-next.1 + - @backstage/plugin-app-visualizer@0.1.6-next.1 + - @backstage/plugin-auth-react@0.1.2-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.1 + - @backstage/plugin-catalog-import@0.10.11-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4-next.1 + - @backstage/plugin-home@0.7.4-next.1 + - @backstage/plugin-kubernetes@0.11.10-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.1 + - @backstage/plugin-org@0.6.25-next.1 + - @backstage/plugin-search@1.4.11-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-signals@0.0.6-next.1 + - @backstage/plugin-techdocs@1.10.5-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + - @backstage/plugin-user-settings@0.8.6-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + +## app-next-example-plugin@0.0.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## example-backend@0.2.98-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.1 + - @backstage/plugin-scaffolder-backend@1.22.5-next.1 + - example-app@0.2.97-next.1 + - @backstage/plugin-search-backend@1.5.8-next.1 + - @backstage/plugin-app-backend@0.3.66-next.1 + - @backstage/plugin-kubernetes-backend@0.17.1-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-backend@0.22.5-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-devtools-backend@0.3.4-next.1 + - @backstage/plugin-events-backend@0.3.5-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-permission-backend@0.5.42-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-proxy-backend@0.4.16-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.4-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.1-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.24-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.27-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/plugin-signals-backend@0.1.4-next.1 + - @backstage/plugin-signals-node@0.1.4-next.1 + - @backstage/plugin-techdocs-backend@1.10.5-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + +## example-backend-next@0.0.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.1 + - @backstage/plugin-notifications-backend@0.2.1-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.1 + - @backstage/plugin-scaffolder-backend@1.22.5-next.1 + - @backstage/plugin-search-backend@1.5.8-next.1 + - @backstage/backend-defaults@0.2.18-next.1 + - @backstage/plugin-app-backend@0.3.66-next.1 + - @backstage/plugin-kubernetes-backend@0.17.1-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-backend@0.22.5-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.4-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.36-next.1 + - @backstage/plugin-devtools-backend@0.3.4-next.1 + - @backstage/plugin-permission-backend@0.5.42-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-proxy-backend@0.4.16-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.24-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/plugin-signals-backend@0.1.4-next.1 + - @backstage/plugin-techdocs-backend@1.10.5-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1-next.1 + +## e2e-test@0.2.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.15-next.1 + +## techdocs-cli-embedded-app@0.2.96-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/cli@0.26.5-next.0 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-techdocs@1.10.5-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + +## @internal/plugin-todo-list@1.0.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + +## @internal/plugin-todo-list-backend@1.0.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 diff --git a/docs/releases/v1.27.0-next.2-changelog.md b/docs/releases/v1.27.0-next.2-changelog.md new file mode 100644 index 0000000000..3c2e688e3b --- /dev/null +++ b/docs/releases/v1.27.0-next.2-changelog.md @@ -0,0 +1,875 @@ +# Release v1.27.0-next.2 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.27.0-next.2](https://backstage.github.io/upgrade-helper/?to=1.27.0-next.2) + +## @backstage/backend-app-api@0.7.3-next.1 + +### Patch Changes + +- 09f8988: Remove explicit `alg` check for user tokens in `verifyToken` +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/cli-node@0.2.5 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + +## @backstage/frontend-app-api@0.7.0-next.2 + +### Minor Changes + +- ddddecb: Extensions in app-config now always affect ordering. Previously, only when enabling disabled extensions did they rise to the top. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7-next.2 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/integration@1.11.0-next.0 + +### Minor Changes + +- 2cc750d: Added `HarnessIntegration` via the `ScmIntegrations` interface. + +## @backstage/repo-tools@0.9.0-next.2 + +### Minor Changes + +- 683870a: Adds 2 new commands `repo schema openapi diff` and `package schema openapi diff`. `repo schema openapi diff` is intended to power a new breaking changes check on pull requests and the package level command allows plugin developers to quickly see new API breaking changes. They're intended to be used in complement with the existing `repo schema openapi verify` command to validate your OpenAPI spec against a variety of things. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-catalog@1.20.0-next.2 + +### Minor Changes + +- 8834daf: Updated the presentation API to return a promise, in addition to the snapshot and observable that were there before. This makes it much easier to consume the API in a non-React context. + +### Patch Changes + +- 4118530: Avoiding pre-loading display total count undefined for table counts +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/plugin-catalog-backend@1.22.0-next.2 + +### Minor Changes + +- f2a2a83: Deprecated the `LocationAnalyzer` type, which has been moved to `@backstage/plugin-catalog-node`. +- f2a2a83: The `/alpha` plugin export has had its implementation of the `catalogAnalysisExtensionPoint` updated to reflect the new API. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-node@1.12.0-next.2 + +### Minor Changes + +- f2a2a83: Added `LocationAnalyzer` type, moved from `@backstage/plugin-catalog-backend`. +- f2a2a83: Breaking change to `/alpha` API where the `catalogAnalysisExtensionPoint` has been reworked. The `addLocationAnalyzer` method has been renamed to `addScmLocationAnalyzer`, and a new `setLocationAnalyzer` method has been added which allows the full `LocationAnalyzer` implementation to be overridden. + +## @backstage/plugin-catalog-react@1.12.0-next.2 + +### Minor Changes + +- 8834daf: Updated the presentation API to return a promise, in addition to the snapshot and observable that were there before. This makes it much easier to consume the API in a non-React context. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7-next.2 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0-next.2 + +### Minor Changes + +- 18f736f: Add examples for `gitlab:projectVariable:create` scaffolder action & improve related tests + +### Patch Changes + +- 8fa8a00: Add merge method and squash option for project creation +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/backend-common@0.22.0-next.2 + +### Patch Changes + +- 2cc750d: Added `HarnessURLReader` with `readUrl` support. +- ccc8851: Added config prop `ensureSchemaExists` to support postgres instances where user can create schemas but not databases. +- Updated dependencies + - @backstage/integration@1.11.0-next.0 + +## @backstage/backend-defaults@0.2.18-next.2 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## @backstage/backend-dynamic-feature-service@0.2.10-next.2 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.22.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## @backstage/backend-test-utils@0.3.8-next.2 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## @backstage/cli@0.26.5-next.1 + +### Patch Changes + +- 2a6f10d: The `versions:bump` command will no longer exit with a non-zero status if the version bump fails due to forbidden duplicate package installations. It will now also provide more information about how to troubleshoot such an error. The set of forbidden duplicates has also been expanded to include all `@backstage/*-app-api` packages. +- c5d7b40: Allow passing a `--require` argument through to the Node process during `package start` +- cc3c518: Fixed an issue causing the `repo fix` command to set an incorrect `workspace` property using Windows +- 812dff0: Add previously-missing semicolon in file templated by `backstage-cli new --select plugin`. +- Updated dependencies + - @backstage/integration@1.11.0-next.0 + +## @backstage/core-components@0.14.7-next.2 + +### Patch Changes + +- a2ee4df: Add `alignGauge` prop to the `GaugeCard`, and a small size version. When `alignGauge` is `'bottom'` the gauge will vertically align the gauge in the cards, even when the card titles span across multiple lines. + Add `alignContent` prop to the `InfoCard`, defaulting to `'normal'` with the option of `'bottom'` which vertically aligns the content to the bottom of the card. + +## @backstage/create-app@0.5.15-next.2 + +### Patch Changes + +- Bumped create-app version. + +## @backstage/dev-utils@1.0.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/frontend-test-utils@0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.0-next.2 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/integration-react@1.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-api-docs@0.11.5-next.2 + +### Patch Changes + +- 725ff0b: Fix dark mode text color inside tables in `description:` from OpenAPI definitions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-auth-backend@0.22.5-next.2 + +### Patch Changes + +- 4a0577e: fix: Move config declarations to appropriate auth backend modules +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.10-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.2 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.10-next.2 + +### Patch Changes + +- 4a0577e: fix: Move config declarations to appropriate auth backend modules +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-auth-backend@0.22.5-next.2 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.2 + +### Patch Changes + +- 4a0577e: fix: Move config declarations to appropriate auth backend modules + +## @backstage/plugin-bitbucket-cloud-common@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.3.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.38-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.19-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.6.1-next.2 + +### Patch Changes + +- 0b50143: GitHub push events now schedule a refresh on entities that have a `refresh_key` matching the `catalogPath` config itself. + This allows to support a `catalogPath` configuration that uses glob patterns. +- f2a2a83: Updated to use the new `catalogAnalysisExtensionPoint` API. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/plugin-catalog-backend@1.22.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-catalog-backend-module-github@0.6.1-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.15-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.15-next.4 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/plugin-catalog-backend@1.22.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.36-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/plugin-catalog-backend@1.22.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.2 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-catalog-graph@0.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-catalog-import@0.10.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/plugin-devtools-backend@0.3.4-next.2 + +### Patch Changes + +- 036feca: Added discovery property to the readme documentation to ensure that it will build when setting it up as new to a Backstage instance +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-events-node@0.3.4-next.2 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used + +## @backstage/plugin-home@0.7.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-kubernetes@0.11.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + +## @backstage/plugin-kubernetes-backend@0.17.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-kubernetes-cluster@0.0.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + +## @backstage/plugin-notifications@0.2.1-next.2 + +### Patch Changes + +- 42eaf63: Increase default and allow modifying notification snackbar auto hide duration +- Updated dependencies + - @backstage/core-components@0.14.7-next.2 + +## @backstage/plugin-notifications-backend@0.2.1-next.2 + +### Patch Changes + +- d541ff6: Fixed email processor `esm` issue and config reading +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## @backstage/plugin-notifications-backend-module-email@0.0.1-next.1 + +### Patch Changes + +- d541ff6: Fixed email processor `esm` issue and config reading +- e538b10: Support relative links in notifications sent via email +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-org@0.6.25-next.2 + +### Patch Changes + +- 99e6105: Fix ownership card sometimes locking up for complex org structures +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-org-react@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + +## @backstage/plugin-scaffolder@1.19.4-next.2 + +### Patch Changes + +- 762141c: Fixed a bug where the `MultiEntityPicker` was not able to be set as required +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-scaffolder-react@1.8.5-next.2 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/plugin-scaffolder-backend@1.22.6-next.2 + +### Patch Changes + +- e4b50ab: Scaffolder workspace serialization +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.10-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.8-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.10-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.8-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.2 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8-next.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.42-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.1-next.0 + +### Patch Changes + +- 503d769: Add a new scaffolder action to allow sending notifications from templates +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-node@0.4.4-next.2 + +### Patch Changes + +- e4b50ab: Scaffolder workspace serialization +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-scaffolder-react@1.8.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + +## @backstage/plugin-search@1.4.11-next.2 + +### Patch Changes + +- 0501243: Added `aria-label` attribute to DialogTitle element and set `aria-modal` attribute to `true` for improved accessibility in the search modal. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + +## @backstage/plugin-search-backend@1.5.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/repo-tools@0.9.0-next.2 + +## @backstage/plugin-search-backend-module-catalog@0.1.24-next.2 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- 5dc5f4f: Allow the `tokenManager` parameter to be optional when instantiating collator +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + +## @backstage/plugin-search-backend-module-techdocs@0.1.23-next.2 + +### Patch Changes + +- 5dc5f4f: Allow the `tokenManager` parameter to be optional when instantiating collator +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-techdocs-node@1.12.4-next.2 + +## @backstage/plugin-signals-backend@0.1.4-next.2 + +### Patch Changes + +- 845d56a: Improved signal lifecycle management and added server side pinging of connections +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## @backstage/plugin-techdocs@1.10.5-next.2 + +### Patch Changes + +- 5863cf7: The `techdocs.builder` config is now optional and it will default to `local`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.5-next.2 + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/plugin-techdocs-backend@1.10.5-next.2 + +### Patch Changes + +- 5863cf7: The `techdocs.builder` config is now optional and it will default to `local`. +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.2 + - @backstage/plugin-techdocs-node@1.12.4-next.2 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/integration-react@1.1.27-next.0 + +## @backstage/plugin-techdocs-node@1.12.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/integration@1.11.0-next.0 + +## @backstage/plugin-user-settings@0.8.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## example-app@0.2.97-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.5-next.1 + - @backstage/frontend-app-api@0.7.0-next.2 + - @backstage/plugin-techdocs@1.10.5-next.2 + - @backstage/plugin-notifications@0.2.1-next.2 + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/plugin-api-docs@0.11.5-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/plugin-scaffolder@1.19.4-next.2 + - @backstage/plugin-search@1.4.11-next.2 + - @backstage/plugin-org@0.6.25-next.2 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.2 + - @backstage/plugin-catalog-import@0.10.11-next.2 + - @backstage/plugin-home@0.7.4-next.2 + - @backstage/plugin-kubernetes@0.11.10-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.2 + - @backstage/plugin-scaffolder-react@1.8.5-next.2 + - @backstage/plugin-user-settings@0.8.6-next.2 + - @backstage/integration-react@1.1.27-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.2 + +## example-app-next@0.0.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.5-next.1 + - @backstage/frontend-app-api@0.7.0-next.2 + - @backstage/plugin-techdocs@1.10.5-next.2 + - @backstage/plugin-notifications@0.2.1-next.2 + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/plugin-api-docs@0.11.5-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/plugin-scaffolder@1.19.4-next.2 + - @backstage/plugin-search@1.4.11-next.2 + - @backstage/plugin-org@0.6.25-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.2 + - @backstage/plugin-catalog-import@0.10.11-next.2 + - @backstage/plugin-home@0.7.4-next.2 + - @backstage/plugin-kubernetes@0.11.10-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.2 + - @backstage/plugin-scaffolder-react@1.8.5-next.2 + - @backstage/plugin-user-settings@0.8.6-next.2 + - @backstage/integration-react@1.1.27-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.2 + +## example-backend-legacy@0.2.98-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0-next.2 + - @backstage/plugin-catalog-backend@1.22.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-devtools-backend@0.3.4-next.2 + - @backstage/plugin-scaffolder-backend@1.22.6-next.2 + - @backstage/plugin-signals-backend@0.1.4-next.2 + - @backstage/plugin-auth-backend@0.22.5-next.2 + - @backstage/plugin-techdocs-backend@1.10.5-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.2 + - @backstage/plugin-kubernetes-backend@0.17.1-next.2 + - @backstage/plugin-search-backend@1.5.8-next.2 + - example-app@0.2.97-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.2 + +## techdocs-cli-embedded-app@0.2.96-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.5-next.1 + - @backstage/plugin-techdocs@1.10.5-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration-react@1.1.27-next.0 diff --git a/docs/releases/v1.27.0.md b/docs/releases/v1.27.0.md new file mode 100644 index 0000000000..123d9663ad --- /dev/null +++ b/docs/releases/v1.27.0.md @@ -0,0 +1,83 @@ +--- +id: v1.27.0 +title: v1.27.0 +description: Backstage Release v1.27.0 +--- + +These are the release notes for the v1.27.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 + +### Backend System Deprecations + +As part of the [work towards a stable 1.0 release of the new backend system](https://github.com/backstage/backstage/issues/24493), we will deprecate and move or remove several utilities from `@backstage/backend-common`. This release contains a few of these deprecations, with more to be expected in the future. The long-term goal is to completely deprecate and remove the `@backstage/backend-common` package. + +### Hierarchical Domains + +The Backstage System Model has been tweaked with the addition of a hierarchy of `Domain` entities. The change includes a new `spec.subdomainOf` property on the `Domain` entity, which can be used to express that a domain has a `partOf` (and conversely, `hasPart`) relation toward another domain. + +Contributed by [@dawngerpony](https://github.com/dawngerpony) and [@janogonzalez](https://github.com/janogonzalez) in [#17125](https://github.com/backstage/backstage/pull/17125). + +### Scaffolder workspace serialization + +Added experimental support for serialization of workspaces in the scaffolder. By serializing the workspace, it is possible to re-run the task in a non-sticky way. This means that the task can be restored and retried on a different scaffolder task worker. + +To enable this feature, set the `EXPERIMENTAL_workspaceSerialization` option to `true` in the `scaffolder` section of the `app-config.yaml` file: + +```yaml +scaffolder: + EXPERIMENTAL_workspaceSerialization: true +``` + +Contributed by [@acierto](https://github.com/acierto) in [#24570](https://github.com/backstage/backstage/pull/24570). + +### Scaffolder `notification:send` action + +The new `notification:send` action allows sending notifications from templates. This can be used to send notifications to users when executing a template. Please note that the notifications system is still under development. + +To install this action, add the new module to your backend: + +```diff ++ backend.add(import('@backstage/plugin-scaffolder-backend-module-notifications')); +``` + +Contributed by [@drodil](https://github.com/drodil) in [#24588](https://github.com/backstage/backstage/pull/24588). + +### Backend Authentication + +The requirement to configure a secret for backend authentication in production has been removed. It is now only needed if you rely on the [legacy authentication mechanism](https://backstage.io/docs/auth/service-to-service-auth#external-callers-legacy). If you don’t configure any secrets you will also not be able to generate tokens with the `TokenManager` service, although use of this service is discouraged as it has been replaced by the `AuthService`. + +### User Authentication + +The `auth` backend plugin now provides an `authOwnershipResolutionExtensionPoint` that lets you override the default ownership resolution used by sign-in resolvers. This allows you to customize this logic for all sign-in resolvers without replacing them. + +Contributed by [@drodil](https://github.com/drodil) in [#22765](https://github.com/backstage/backstage/pull/22765). + +### Events support for GitLab Entity and Org Discovery + +The `GitlabDiscoveryEntityProvider` and `GitlabOrgDiscoveryEntityProvider` can now be configured to receive events from GitLab. This allows for the automatic discovery of entities in Backstage when groups or users are created or updated in GitLab. + +Contributed by [@elaine-mattos](https://github.com/elaine-mattos) in [#23373](https://github.com/backstage/backstage/pull/23373). + +## 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.27.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.28.0-next.0-changelog.md b/docs/releases/v1.28.0-next.0-changelog.md new file mode 100644 index 0000000000..69c17d7c7d --- /dev/null +++ b/docs/releases/v1.28.0-next.0-changelog.md @@ -0,0 +1,2101 @@ +# Release v1.28.0-next.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.28.0-next.0](https://backstage.github.io/upgrade-helper/?to=1.28.0-next.0) + +## @backstage/plugin-catalog-backend@1.23.0-next.0 + +### Minor Changes + +- c7528b0: Pass through `EventsService` too in the new backend system + +### Patch Changes + +- 8869b8e: Updated local development setup. +- 1779188: Start using the `isDatabaseConflictError` helper from the `@backstage/backend-plugin-api` package in order to avoid dependency with the soon to deprecate `@backstage/backend-common` package. +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/backend-openapi-utils@0.1.12-next.0 + - @backstage/plugin-catalog-node@1.12.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@1.11.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-proxy-backend@0.5.0-next.0 + +### Minor Changes + +- 88480e4: **BREAKING**: The proxy backend plugin is now protected by Backstage auth, by + default. Unless specifically configured (see below), all proxy endpoints will + reject requests immediately unless a valid Backstage user or service token is + passed along with the request. This aligns the proxy with how other Backstage + backends behave out of the box, and serves to protect your upstreams from + unauthorized access. + + A proxy configuration section can now look as follows: + + ```yaml + proxy: + endpoints: + '/pagerduty': + target: https://api.pagerduty.com + credentials: require # NEW! + headers: + Authorization: Token token=${PAGERDUTY_TOKEN} + ``` + + There are three possible `credentials` settings at this point: + + - `require`: Callers must provide Backstage user or service credentials with + each request. The credentials are not forwarded to the proxy target. + - `forward`: Callers must provide Backstage user or service credentials with + each request, and those credentials are forwarded to the proxy target. + - `dangerously-allow-unauthenticated`: No Backstage credentials are required to + access this proxy target. The target can still apply its own credentials + checks, but the proxy will not help block non-Backstage-blessed callers. If + you also add `allowedHeaders: ['Authorization']` to an endpoint configuration, + then the Backstage token (if provided) WILL be forwarded. + + The value `dangerously-allow-unauthenticated` was the old default. + + The value `require` is the new default, so requests that were previously + permitted may now start resulting in `401 Unauthorized` responses. If you have + `backend.auth.dangerouslyDisableDefaultAuthPolicy` set to `true`, this does not + apply; the proxy will behave as if all endpoints were set to + `dangerously-allow-unauthenticated`. + + If you have proxy endpoints that require unauthenticated access still, please + add `credentials: dangerously-allow-unauthenticated` to their declarations in + your app-config. + +### Patch Changes + +- 8869b8e: Updated local development setup. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/app-defaults@1.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/plugin-permission-react@0.4.22 + +## @backstage/backend-app-api@0.7.6-next.0 + +### Patch Changes + +- b7de623: Fixed a potential crash when passing an object with a `null` prototype as log meta. +- 7d30d95: Fixing issue with log meta fields possibly being circular refs +- 6a576dc: Stop using `getVoidLogger` in tests to reduce the dependency on the soon-to-deprecate `backstage-common` package. +- 6551b3d: Deprecated core service factories and implementations and moved them over to + subpath exports on `@backstage/backend-defaults` instead. E.g. + `@backstage/backend-defaults/scheduler` is where the service factory and default + implementation of `coreServices.scheduler` now lives. +- d617103: Updating the logger redaction message to something less dramatic +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-common@0.22.1-next.0 + +### Patch Changes + +- c6c0919: Updated configuration schema to include the `useRedisSets` cache config option. +- 1779188: In preparation to the new backend system stable release, the `isDatabaseConflictError` helper have been moved to the `@backstage/backend-plugin-api` package and deprecated from `@backstage/backend-common`. +- 8869b8e: We are deprecating the legacy `createServiceBuilder` factory, so if you are still using it, please checkout the migration guide and [migrate](https://backstage.io/docs/backend-system/building-plugins-and-modules/migrating) your plugin to use the new backend system. +- 3bd04bb: We are deprecating the legacy router handlers and contexts in preparation for the new backend system stable release. +- 6a576dc: Deprecate legacy service logger helpers and stop using `getVoidLogger` in tests. +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.19-next.0 + +### Patch Changes + +- 6551b3d: Added core service factories and implementations from + `@backstage/backend-app-api`. They are now available as subpath exports, e.g. + `@backstage/backend-defaults/scheduler` is where the service factory and default + implementation of `coreServices.scheduler` now lives. They have been marked as + deprecated in their old locations. +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-dynamic-feature-service@0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-events-backend@0.3.6-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/plugin-app-node@0.1.19-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/backend-openapi-utils@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/errors@1.2.4 + +## @backstage/backend-plugin-api@0.6.19-next.0 + +### Patch Changes + +- 6551b3d: Moved the declaration of the `SchedulerService` here, along with prefixed versions of all of the types it depends on, from `@backstage/backend-tasks` +- 1779188: Start using the `isDatabaseConflictError` helper from the `@backstage/backend-plugin-api` package in order to avoid dependency with the soon to deprecate `@backstage/backend-common` package. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/backend-tasks@0.5.24-next.0 + +### Patch Changes + +- 736bc3c: Marked all exports as deprecated and pointed at `@backstage/backend-plugin-api` and `@backstage/backend-defaults` +- 6a576dc: Deprecate the legacy `TaskScheduler.fromConfig` method and stop using the `getVoidlogger` in tests files to reduce the dependency on the soon-to-deprecate `backstage-common` package. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.3.9-next.0 + +### Patch Changes + +- 6a576dc: Fix the logger service mock to prevent returning `undefined` from the `child` method. +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/cli@0.26.6-next.0 + +### Patch Changes + +- 009da47: Fix `versions:check --fix` when `yarn.lock` has multiple joint versions in the same section +- 9ee948a: Bump `esbuild` target for package builds to `ES2022`. +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.11.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/cli-node@0.2.6-next.0 + +### Patch Changes + +- 93be042: Upgraded @yarnpkg/parsers to stable 3.0 +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/version-bridge@1.0.8 + +## @backstage/core-components@0.14.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.16-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/frontend-app-api@0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-plugin-api@0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.1-next.0 + - @backstage/test-utils@1.5.6-next.0 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-techdocs-node@1.12.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + +## @backstage/test-utils@1.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-permission-react@0.4.22 + +## @backstage/theme@0.5.6-next.0 + +### Patch Changes + +- 702fa7d: Internal refactor to fix an issue where the MUI 5 `v5-` class prefixing gets removed by tree shaking. + +## @backstage/plugin-api-docs@0.11.6-next.0 + +### Patch Changes + +- 96cd13e: `DefaultApiExplorerPage` now accepts an optional `ownerPickerMode` for toggling the behavior of the `EntityOwnerPicker`, exposing a new mode `` particularly suitable for larger catalogs. In this new mode, `EntityOwnerPicker` will display all the users and groups present in the catalog. +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/plugin-catalog@1.20.1-next.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-permission-react@0.4.22 + +## @backstage/plugin-app-backend@0.3.68-next.0 + +### Patch Changes + +- 8869b8e: Updated local development setup. +- 82c2b90: Restore the support of external config schema in the router of the `app-backend` plugin, which was broken in release `1.26.0`. + This support is critical for dynamic frontend plugins to have access to their config values. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-app-node@0.1.19-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-app-node@0.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config-loader@1.8.0 + +## @backstage/plugin-app-visualizer@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + +## @backstage/plugin-auth-backend@0.22.6-next.0 + +### Patch Changes + +- 8869b8e: Updated local development setup. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.11-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.1.10-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.11-next.0 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.14-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.12-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.14-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.12-next.0 + - @backstage/plugin-catalog-node@1.12.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.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-auth-backend@0.22.6-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-auth-backend@0.22.6-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-auth-node@0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-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.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog@1.20.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/integration-react@1.1.27 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-permission-react@0.4.22 + - @backstage/plugin-scaffolder-common@1.5.2 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-catalog-backend-module-aws@0.3.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-catalog-backend-module-azure@0.1.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/backend-openapi-utils@0.1.12-next.0 + - @backstage/plugin-catalog-node@1.12.1-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.6-next.0 + +### Patch Changes + +- 6a576dc: Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.11.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.19 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-catalog-backend-module-github@0.6.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-backend-module-github@0.6.2-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.17-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.35-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-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.23 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.11.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.23 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-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.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-scaffolder-common@1.5.2 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.1 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-catalog-graph@0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-catalog-import@0.11.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-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.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/integration@1.11.0 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-catalog-node@1.12.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-permission-node@0.7.30-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.23 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-catalog-react@1.12.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/integration-react@1.1.27 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-permission-react@0.4.22 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + +## @backstage/plugin-config-schema@0.1.56-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/plugin-devtools-common@0.1.9 + - @backstage/plugin-permission-react@0.4.22 + +## @backstage/plugin-devtools-backend@0.3.5-next.0 + +### Patch Changes + +- 8869b8e: Updated local development setup. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.9 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-events-backend@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend-module-azure@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + +## @backstage/plugin-events-backend-module-github@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-test-utils@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-events-node@0.3.5-next.0 + +### Patch Changes + +- 6a576dc: Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + +## @backstage/plugin-home@0.7.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-home-react@0.1.14-next.0 + +## @backstage/plugin-home-react@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + +## @backstage/plugin-kubernetes@0.11.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-kubernetes-common@0.7.6 + - @backstage/plugin-kubernetes-react@0.3.6-next.0 + +## @backstage/plugin-kubernetes-backend@0.17.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-kubernetes-node@0.1.13-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-catalog-node@1.12.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-kubernetes-common@0.7.6 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-kubernetes-cluster@0.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-kubernetes-common@0.7.6 + - @backstage/plugin-kubernetes-react@0.3.6-next.0 + +## @backstage/plugin-kubernetes-node@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-kubernetes-react@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.6 + +## @backstage/plugin-notifications@0.2.2-next.0 + +### Patch Changes + +- 7f02684: Do not always show scrollbars in notification description +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.3 + - @backstage/plugin-signals-react@0.0.3 + +## @backstage/plugin-notifications-backend@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-notifications-node@0.1.5-next.0 + - @backstage/plugin-signals-node@0.1.5-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-notifications-common@0.0.3 + +## @backstage/plugin-notifications-backend-module-email@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-notifications-node@0.1.5-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.3 + +## @backstage/plugin-notifications-node@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-signals-node@0.1.5-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.3 + +## @backstage/plugin-org@0.6.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-org-react@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-permission-backend@0.5.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-permission-node@0.7.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-scaffolder@1.20.1-next.0 + +### Patch Changes + +- 612a453: Change owner to project for azure host +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/integration@1.11.0 + - @backstage/integration-react@1.1.27 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-permission-react@0.4.22 + - @backstage/plugin-scaffolder-common@1.5.2 + +## @backstage/plugin-scaffolder-backend@1.22.8-next.0 + +### Patch Changes + +- 7d30d95: Fixing issue with log meta fields possibly being circular refs +- d617103: Updating the logger redaction message to something less dramatic +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.11-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.9-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.9-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.9-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.11-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.9-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.0 + - @backstage/plugin-catalog-node@1.12.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@1.11.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-scaffolder-common@1.5.2 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.9-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.9-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.0 + +### Patch Changes + +- f145a04: Added handling for dry run to githubPullRequest and githubWebhook and added tests for this functionality +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-notifications-node@0.1.5-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/plugin-notifications-common@0.0.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.1.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.2 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.5-next.0 + +### Patch Changes + +- 6a576dc: Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-test-utils@0.3.9-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-react@1.8.6-next.0 + +### Patch Changes + +- 86dc29d: Links that are rendered in the markdown in the `ScaffolderField` component are now opened in new tabs. +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-scaffolder-common@1.5.2 + +## @backstage/plugin-search@1.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend@1.5.10-next.0 + +### Patch Changes + +- 8869b8e: Updated local development setup. +- 5b6f979: Split backend search plugin startup into "init" and "start" stages to ensure necessary initialization has happened before startup +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/backend-defaults@0.2.19-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/repo-tools@0.9.1-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/backend-openapi-utils@0.1.12-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend-module-catalog@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-catalog-node@1.12.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.23 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend-module-elasticsearch@1.4.2-next.0 + +### Patch Changes + +- 6a576dc: Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend-module-explore@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend-module-pg@0.5.28-next.0 + +### Patch Changes + +- 6a576dc: Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend-module-techdocs@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-techdocs-node@1.12.5-next.0 + - @backstage/plugin-catalog-node@1.12.1-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.23 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-backend-node@1.2.24-next.0 + +### Patch Changes + +- 6a576dc: Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. +- 5b6f979: Split backend search plugin startup into "init" and "start" stages to ensure necessary initialization has happened before startup +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-search-react@1.7.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-signals@0.0.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.3 + +## @backstage/plugin-signals-backend@0.1.5-next.0 + +### Patch Changes + +- 6a576dc: Replace the usage of `getVoidLogger` with `mockServices.logger.mock` in order to remove the dependency with the soon-to-be-deprecated `backend-common` package. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-signals-node@0.1.5-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-signals-node@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-techdocs@1.10.6-next.0 + +### Patch Changes + +- 654af4a: mkdocs-material have updated their CSS variable template, and a few are unset in Backstage. This patch adds the missing variables to ensure coverage. +- 96cd13e: `TechDocsIndexPage` now accepts an optional `ownerPickerMode` for toggling the behavior of the `EntityOwnerPicker`, exposing a new mode `` particularly suitable for larger catalogs. In this new mode, `EntityOwnerPicker` will display all the users and groups present in the catalog. +- e40bd9a: Fixed bug in CopyToClipboardButton component where positioning of the "Copy to clipboard" button in techdocs code snippets was broken in some cases +- 1256d88: Fix weird opening behaviour of the component. +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/integration@1.11.0 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-auth-react@0.1.3-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.6-next.0 + - @backstage/test-utils@1.5.6-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog@1.20.1-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-techdocs-backend@1.10.6-next.0 + +### Patch Changes + +- 8869b8e: Updated local development setup. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.0 + - @backstage/plugin-techdocs-node@1.12.5-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@1.11.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-permission-common@0.7.13 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration@1.11.0 + - @backstage/integration-react@1.1.27 + +## @backstage/plugin-techdocs-node@1.12.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.11 + +## @backstage/plugin-techdocs-react@1.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-user-settings@0.8.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-user-settings-backend@0.2.18-next.0 + +### Patch Changes + +- 8869b8e: Updated local development setup. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## example-app@0.2.98-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.6-next.0 + - @backstage/plugin-notifications@0.2.2-next.0 + - @backstage/plugin-scaffolder-react@1.8.6-next.0 + - @backstage/theme@0.5.6-next.0 + - @backstage/plugin-api-docs@0.11.6-next.0 + - @backstage/cli@0.26.6-next.0 + - @backstage/plugin-scaffolder@1.20.1-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/frontend-app-api@0.7.1-next.0 + - @backstage/plugin-home@0.7.5-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/plugin-signals@0.0.7-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/plugin-user-settings@0.8.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-auth-react@0.1.3-next.0 + - @backstage/plugin-catalog@1.20.1-next.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-graph@0.4.6-next.0 + - @backstage/plugin-catalog-import@0.11.1-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.5-next.0 + - @backstage/plugin-devtools@0.1.15-next.0 + - @backstage/plugin-kubernetes@0.11.11-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.0 + - @backstage/plugin-org@0.6.26-next.0 + - @backstage/plugin-permission-react@0.4.22 + - @backstage/plugin-search@1.4.12-next.0 + - @backstage/plugin-search-common@1.2.11 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.11-next.0 + +## example-app-next@0.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.6-next.0 + - @backstage/plugin-notifications@0.2.2-next.0 + - @backstage/plugin-scaffolder-react@1.8.6-next.0 + - @backstage/theme@0.5.6-next.0 + - @backstage/plugin-api-docs@0.11.6-next.0 + - @backstage/cli@0.26.6-next.0 + - @backstage/plugin-scaffolder@1.20.1-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/frontend-app-api@0.7.1-next.0 + - @backstage/plugin-home@0.7.5-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/plugin-signals@0.0.7-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/plugin-user-settings@0.8.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-app-visualizer@0.1.7-next.0 + - @backstage/plugin-auth-react@0.1.3-next.0 + - @backstage/plugin-catalog@1.20.1-next.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-graph@0.4.6-next.0 + - @backstage/plugin-catalog-import@0.11.1-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.5-next.0 + - @backstage/plugin-kubernetes@0.11.11-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.0 + - @backstage/plugin-org@0.6.26-next.0 + - @backstage/plugin-permission-react@0.4.22 + - @backstage/plugin-search@1.4.12-next.0 + - @backstage/plugin-search-common@1.2.11 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.11-next.0 + +## app-next-example-plugin@0.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/frontend-plugin-api@0.6.6-next.0 + +## example-backend@0.0.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.0 + - @backstage/plugin-devtools-backend@0.3.5-next.0 + - @backstage/plugin-techdocs-backend@1.10.6-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-search-backend@1.5.10-next.0 + - @backstage/plugin-proxy-backend@0.5.0-next.0 + - @backstage/plugin-auth-backend@0.22.6-next.0 + - @backstage/plugin-app-backend@0.3.68-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/plugin-signals-backend@0.1.5-next.0 + - @backstage/backend-defaults@0.2.19-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-backend@1.22.8-next.0 + - @backstage/plugin-kubernetes-backend@0.17.2-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.2-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.5-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.37-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.0 + - @backstage/plugin-notifications-backend@0.2.2-next.0 + - @backstage/plugin-permission-backend@0.5.43-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.16-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.16-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-permission-common@0.7.13 + +## example-backend-legacy@0.2.99-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-devtools-backend@0.3.5-next.0 + - @backstage/plugin-techdocs-backend@1.10.6-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-search-backend@1.5.10-next.0 + - @backstage/plugin-proxy-backend@0.5.0-next.0 + - @backstage/plugin-auth-backend@0.22.6-next.0 + - @backstage/plugin-app-backend@0.3.68-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.2-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.28-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/plugin-signals-backend@0.1.5-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-scaffolder-backend@1.22.8-next.0 + - @backstage/plugin-kubernetes-backend@0.17.2-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.0 + - example-app@0.2.98-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.0 + - @backstage/plugin-events-backend@0.3.6-next.0 + - @backstage/plugin-permission-backend@0.5.43-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.20-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.36-next.0 + - @backstage/plugin-signals-node@0.1.5-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.11.0 + - @backstage/plugin-permission-common@0.7.13 + +## e2e-test@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.16-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.97-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.6-next.0 + - @backstage/theme@0.5.6-next.0 + - @backstage/cli@0.26.6-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/test-utils@1.5.6-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog@1.20.1-next.0 + +## @internal/plugin-todo-list@1.0.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + +## @internal/plugin-todo-list-backend@1.0.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/errors@1.2.4 diff --git a/docs/releases/v1.28.0-next.1-changelog.md b/docs/releases/v1.28.0-next.1-changelog.md new file mode 100644 index 0000000000..cb5502738d --- /dev/null +++ b/docs/releases/v1.28.0-next.1-changelog.md @@ -0,0 +1,1014 @@ +# Release v1.28.0-next.1 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.28.0-next.1](https://backstage.github.io/upgrade-helper/?to=1.28.0-next.1) + +## @backstage/backend-common@0.23.0-next.1 + +### Minor Changes + +- 02103be: Deprecated and moved over core services to `@backstage/backend-defaults` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/backend-defaults@0.3.0-next.1 + +### Minor Changes + +- 02103be: Deprecated and moved over core services to `@backstage/backend-defaults` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/backend-test-utils@0.4.0-next.1 + +### Minor Changes + +- 805cbe7: Added `TestCaches` that functions just like `TestDatabases` + +### Patch Changes + +- 9e63318: Made it possible to give access restrictions to `mockCredentials.service` +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.6.0-next.1 + +### Minor Changes + +- debcc8c: Migrate LDAP catalog module to the new backend system. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-import@0.12.0-next.1 + +### Minor Changes + +- 4f92394: Migrate from identityApi to fetchApi in frontend plugins. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-kubernetes-backend@0.18.0-next.1 + +### Minor Changes + +- 0177f75: Update kubernetes plugins to use autoscaling/v2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-kubernetes-common@0.8.0-next.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-kubernetes-node@0.1.13-next.1 + +## @backstage/plugin-kubernetes-common@0.8.0-next.0 + +### Minor Changes + +- 0177f75: Update kubernetes plugins to use autoscaling/v2 + +## @backstage/plugin-kubernetes-react@0.4.0-next.1 + +### Minor Changes + +- 4f92394: Migrate from identityApi to fetchApi in frontend plugins. +- 0177f75: Update kubernetes plugins to use autoscaling/v2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.8.0-next.0 + +## @backstage/plugin-notifications-backend@0.3.0-next.1 + +### Minor Changes + +- 07a789b: adding filtering of notifications by processors + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-notifications-node@0.2.0-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-signals-node@0.1.5-next.1 + +## @backstage/plugin-notifications-backend-module-email@0.1.0-next.1 + +### Minor Changes + +- 07a789b: add notification filters + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-notifications-node@0.2.0-next.1 + - @backstage/backend-common@0.23.0-next.1 + +## @backstage/plugin-notifications-node@0.2.0-next.1 + +### Minor Changes + +- 07a789b: add notifications filtering by processors + +### Patch Changes + +- 1354d81: Use `node-fetch` instead of native fetch, as per +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-signals-node@0.1.5-next.1 + +## @backstage/backend-app-api@0.7.6-next.1 + +### Patch Changes + +- 398b82a: Add support for JWKS tokens in ExternalTokenHandler. +- 9e63318: Added an optional `accessRestrictions` to external access service tokens and service principals in general, such that you can limit their access to certain plugins or permissions. +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/backend-dynamic-feature-service@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-events-backend@0.3.6-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## @backstage/backend-plugin-api@0.6.19-next.1 + +### Patch Changes + +- 9e63318: Added an optional `accessRestrictions` to external access service tokens and service principals in general, such that you can limit their access to certain plugins or permissions. +- 0665b7e: Renamed `BackendPluginConfig`, `BackendModuleConfig`, and `ExtensionPointConfig` respectively to `CreateBackendPluginOptions`, `CreateBackendModuleOptions`, and `CreateExtensionPointOptions` to standardize frontend and backend factories signatures. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/backend-tasks@0.5.24-next.1 + +### Patch Changes + +- ed473cd: Updated the `TaskScheduleDefinitionConfig` deprecated comment to point to `SchedulerServiceTaskScheduleDefinitionConfig` +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + +## @backstage/cli@0.26.7-next.1 + +### Patch Changes + +- 788eca7: Fix readme for new plugins created using cli +- c00f7ee: Fix issue with `esm` loaded dependencies being different from the `cjs` import for Vite dependencies +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + +## @backstage/create-app@0.5.16-next.1 + +### Patch Changes + +- Bumped create-app version. + +## @backstage/repo-tools@0.9.1-next.1 + +### Patch Changes + +- 8721a02: Add `--client-additional-properties` option to `openapi generate` command +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + +## @techdocs/cli@1.8.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-techdocs-node@1.12.5-next.1 + +## @backstage/plugin-app-backend@0.3.68-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/plugin-auth-backend@0.22.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.2-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.11-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.11-next.1 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.14-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.14-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.12-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.1.10-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.12-next.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-backend@0.22.6-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.2-next.1 + +### Patch Changes + +- 1354d81: Use `node-fetch` instead of native fetch, as per +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-backend@0.22.6-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/plugin-auth-node@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + +## @backstage/plugin-catalog@1.20.1-next.1 + +### Patch Changes + +- a2d2649: Export `catalogTranslationRef` under `/alpha` + +- bcec60f: updated the ContextMenu, ActionsPage, OngoingTask and TemplateCard frontend components to support the new scaffolder permissions: + + - `scaffolder.task.create` + - `scaffolder.task.cancel` + - `scaffolder.task.read` + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.3-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-catalog-backend@1.23.0-next.1 + +### Patch Changes + +- d779e3b: Added a regex test to check commit hash. If url is from git commit branch ignore the edit url. +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-kubernetes-common@0.8.0-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-kubernetes-common@0.8.0-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.6.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-backend-module-github@0.6.2-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.17-next.1 + +### Patch Changes + +- 150fc77: Fixed an issue in `GitlabOrgDiscoveryEntityProvider` where a missing `orgEnabled` config key was throwing an error. +- f271164: Fixed an issue in `GitlabDiscoveryEntityProvider` where the fallback branch was taking precedence over the GitLab default branch. +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.17-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-scaffolder-common@1.5.3-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + +## @backstage/plugin-devtools-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/config-loader@1.8.0 + +## @backstage/plugin-events-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-kubernetes@0.11.11-next.1 + +### Patch Changes + +- 4f92394: Migrate from identityApi to fetchApi in frontend plugins. +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.4.0-next.1 + - @backstage/plugin-kubernetes-common@0.8.0-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-kubernetes-cluster@0.0.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.4.0-next.1 + - @backstage/plugin-kubernetes-common@0.8.0-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-kubernetes-node@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-kubernetes-common@0.8.0-next.0 + +## @backstage/plugin-notifications@0.2.2-next.1 + +### Patch Changes + +- 6d196b4: Fixes performance issue with Notifications title counter. + +## @backstage/plugin-permission-backend@0.5.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/plugin-permission-node@0.7.30-next.1 + +### Patch Changes + +- 9e63318: Ensure that service token access restrictions, when present, are taken into account +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## @backstage/plugin-proxy-backend@0.5.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + +## @backstage/plugin-scaffolder@1.20.2-next.1 + +### Patch Changes + +- 75dcd7e: Fixing bug in `formData` type as it should be `optional` as it's possibly undefined + +- bcec60f: updated the ContextMenu, ActionsPage, OngoingTask and TemplateCard frontend components to support the new scaffolder permissions: + + - `scaffolder.task.create` + - `scaffolder.task.cancel` + - `scaffolder.task.read` + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.7-next.1 + - @backstage/plugin-scaffolder-common@1.5.3-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-scaffolder-backend@1.22.8-next.1 + +### Patch Changes + +- bcec60f: added the following new permissions to the scaffolder backend endpoints: + + - `scaffolder.task.create` + - `scaffolder.task.cancel` + - `scaffolder.task.read` + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.9-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.1 + - @backstage/plugin-scaffolder-common@1.5.3-next.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.9-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.9-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.9-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.11-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.9-next.1 + +### Patch Changes + +- 1354d81: Use `node-fetch` instead of native fetch, as per +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.1 + +### Patch Changes + +- 829e0ec: Add new `gitlab:pipeline:trigger` action to trigger GitLab pipelines. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-notifications-node@0.2.0-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.27-next.1 + +### Patch Changes + +- 1354d81: Use `node-fetch` instead of native fetch, as per +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-common@1.5.3-next.0 + +### Patch Changes + +- bcec60f: added the following new permissions to the scaffolder backend endpoints: + + - `scaffolder.task.create` + - `scaffolder.task.cancel` + - `scaffolder.task.read` + +## @backstage/plugin-scaffolder-node@0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-common@1.5.3-next.0 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@0.4.0-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + +## @backstage/plugin-scaffolder-react@1.8.7-next.1 + +### Patch Changes + +- 75dcd7e: Fixing bug in `formData` type as it should be `optional` as it's possibly undefined +- 928cfa0: Fixed a typo ' + +## @backstage/plugin-search@1.4.12-next.1 + +### Patch Changes + +- 4f92394: Migrate from identityApi to fetchApi in frontend plugins. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## @backstage/plugin-search-backend@1.5.10-next.1 + +### Patch Changes + +- 34dc47d: Move @backstage/repo-tools to devDependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-defaults@0.3.0-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## @backstage/plugin-search-backend-module-catalog@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## @backstage/plugin-search-backend-module-elasticsearch@1.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## @backstage/plugin-search-backend-module-explore@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## @backstage/plugin-search-backend-module-pg@0.5.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## @backstage/plugin-search-backend-module-techdocs@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + - @backstage/plugin-techdocs-node@1.12.5-next.1 + +## @backstage/plugin-search-backend-node@1.2.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + +## @backstage/plugin-signals-backend@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-signals-node@0.1.5-next.1 + +## @backstage/plugin-signals-node@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + +## @backstage/plugin-techdocs-backend@1.10.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.1 + - @backstage/plugin-techdocs-node@1.12.5-next.1 + +## @backstage/plugin-techdocs-node@1.12.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + +## @backstage/plugin-user-settings-backend@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## example-app@0.2.98-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.7-next.1 + - @backstage/plugin-catalog-import@0.12.0-next.1 + - @backstage/plugin-kubernetes@0.11.11-next.1 + - @backstage/plugin-search@1.4.12-next.1 + - @backstage/plugin-notifications@0.2.2-next.1 + - @backstage/plugin-scaffolder-react@1.8.7-next.1 + - @backstage/plugin-scaffolder@1.20.2-next.1 + - @backstage/plugin-catalog@1.20.1-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.1 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## example-app-next@0.0.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.7-next.1 + - @backstage/plugin-catalog-import@0.12.0-next.1 + - @backstage/plugin-kubernetes@0.11.11-next.1 + - @backstage/plugin-search@1.4.12-next.1 + - @backstage/plugin-notifications@0.2.2-next.1 + - @backstage/plugin-scaffolder-react@1.8.7-next.1 + - @backstage/plugin-scaffolder@1.20.2-next.1 + - @backstage/plugin-catalog@1.20.1-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.1 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## example-backend@0.0.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/plugin-search-backend@1.5.10-next.1 + - @backstage/backend-defaults@0.3.0-next.1 + - @backstage/plugin-kubernetes-backend@0.18.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/plugin-scaffolder-backend@1.22.8-next.1 + - @backstage/plugin-notifications-backend@0.3.0-next.1 + - @backstage/plugin-app-backend@0.3.68-next.1 + - @backstage/plugin-auth-backend@0.22.6-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.5-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.37-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.1 + - @backstage/plugin-devtools-backend@0.3.5-next.1 + - @backstage/plugin-permission-backend@0.5.43-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.16-next.0 + - @backstage/plugin-proxy-backend@0.5.0-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + - @backstage/plugin-signals-backend@0.1.5-next.1 + - @backstage/plugin-techdocs-backend@1.10.6-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.1 + +## example-backend-legacy@0.2.99-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/plugin-search-backend@1.5.10-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.1 + - @backstage/plugin-kubernetes-backend@0.18.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/plugin-scaffolder-backend@1.22.8-next.1 + - @backstage/plugin-app-backend@0.3.68-next.1 + - @backstage/plugin-auth-backend@0.22.6-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-devtools-backend@0.3.5-next.1 + - @backstage/plugin-events-backend@0.3.6-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-permission-backend@0.5.43-next.1 + - @backstage/plugin-proxy-backend@0.5.0-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.20-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.36-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.2-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.28-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + - @backstage/plugin-signals-backend@0.1.5-next.1 + - @backstage/plugin-techdocs-backend@1.10.6-next.1 + - example-app@0.2.98-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.1 + - @backstage/plugin-signals-node@0.1.5-next.1 + +## @internal/plugin-todo-list-backend@1.0.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 diff --git a/docs/releases/v1.3.0-changelog.md b/docs/releases/v1.3.0-changelog.md index 641fd8422a..e3cdd75024 100644 --- a/docs/releases/v1.3.0-changelog.md +++ b/docs/releases/v1.3.0-changelog.md @@ -883,8 +883,7 @@ ### Patch Changes - 8f7b1835df: Updated dependency `msw` to `^0.41.0`. -- 811ff4bcf4: Updated `swagger-ui-react` to 4.11.1 in order to address a [XSS - vulnerability](https://github.com/advisories/GHSA-hqq7-2q2v-82xq) in `@braintree/sanitize-url` +- 811ff4bcf4: Updated `swagger-ui-react` to 4.11.1 in order to address a [XSS vulnerability](https://github.com/advisories/GHSA-hqq7-2q2v-82xq) in `@braintree/sanitize-url` - Updated dependencies - @backstage/plugin-catalog@1.3.0 - @backstage/plugin-catalog-react@1.1.1 diff --git a/docs/releases/v1.6.0-changelog.md b/docs/releases/v1.6.0-changelog.md index 0308c5fd3d..0532243cbf 100644 --- a/docs/releases/v1.6.0-changelog.md +++ b/docs/releases/v1.6.0-changelog.md @@ -24,9 +24,7 @@ - 1fe6823bb5: Updated dependency `eslint-plugin-jest` to `^27.0.0`. Note that this major update to the Jest plugin contains some breaking changes. - This means that some of your tests may start seeing some new lint errors. [Read - about them - here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). + This means that some of your tests may start seeing some new lint errors. [Read about them here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). These are mostly possible to fix automatically. You can try to run `yarn backstage-cli repo lint --fix` in your repo root to have most or all of them corrected. diff --git a/docs/releases/v1.6.0-next.1-changelog.md b/docs/releases/v1.6.0-next.1-changelog.md index 3a1dc8f1b7..e749e32c98 100644 --- a/docs/releases/v1.6.0-next.1-changelog.md +++ b/docs/releases/v1.6.0-next.1-changelog.md @@ -7,9 +7,7 @@ - 1fe6823bb5: Updated dependency `eslint-plugin-jest` to `^27.0.0`. Note that this major update to the Jest plugin contains some breaking changes. - This means that some of your tests may start seeing some new lint errors. [Read - about them - here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). + This means that some of your tests may start seeing some new lint errors. [Read about them here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). These are mostly possible to fix automatically. You can try to run `yarn backstage-cli repo lint --fix` in your repo root to have most or all of them corrected. diff --git a/docs/releases/v1.7.0-changelog.md b/docs/releases/v1.7.0-changelog.md index 3653484952..47fd8463d6 100644 --- a/docs/releases/v1.7.0-changelog.md +++ b/docs/releases/v1.7.0-changelog.md @@ -926,8 +926,7 @@ Migrating to the stable version of `react-router` is optional for the time being. But if you want to do the same for your existing repository, please - follow [this - guide](https://backstage.io/docs/tutorials/react-router-stable-migration). + follow [this guide](https://backstage.io/docs/tutorials/react-router-stable-migration). - e05e0f021b: Update versions of packages used in the create-app template, to match those in the main repo diff --git a/docs/releases/v1.7.0-next.0-changelog.md b/docs/releases/v1.7.0-next.0-changelog.md index 57b3c64f6f..41d3ebd55f 100644 --- a/docs/releases/v1.7.0-next.0-changelog.md +++ b/docs/releases/v1.7.0-next.0-changelog.md @@ -319,8 +319,7 @@ Migrating to the stable version of `react-router` is optional for the time being. But if you want to do the same for your existing repository, please - follow [this - guide](https://backstage.io/docs/tutorials/react-router-stable-migration). + follow [this guide](https://backstage.io/docs/tutorials/react-router-stable-migration). - e05e0f021b: Update versions of packages used in the create-app template, to match those in the main repo diff --git a/docs/releases/v1.7.0.md b/docs/releases/v1.7.0.md index 56eda8b20d..edd5cbb591 100644 --- a/docs/releases/v1.7.0.md +++ b/docs/releases/v1.7.0.md @@ -22,24 +22,20 @@ backend needs to be supplied with a location analyzer for this use case to continue to function. If you want to make use of this feature, check out the installation instructions -in [the -changelog](https://github.com/backstage/backstage/blob/master/plugins/catalog-import/CHANGELOG.md#090). +in [the changelog](https://github.com/backstage/backstage/blob/master/plugins/catalog-import/CHANGELOG.md#090). Contributed by [@kissmikijr](https://github.com/kissmikijr) in [#13800](https://github.com/backstage/backstage/pull/13800) ### Permission Rule Changes -When defining permission rules, it's now necessary to provide a [Zod -Schema](https://github.com/colinhacks/zod) that specifies the parameters the +When defining permission rules, it's now necessary to provide a [Zod Schema](https://github.com/colinhacks/zod) that specifies the parameters the rule expects. This has been added to help better describe the parameters in the response of the metadata endpoint and to validate the parameters before a rule is executed. The signatures of the rule methods (`apply` and `toQuery`) have changed slightly as well. -You can read more about this in [the permissions -documentation](https://backstage.io/docs/permissions/overview) and [the -changelog](https://github.com/backstage/backstage/blob/master/plugins/permission-node/CHANGELOG.md#070). +You can read more about this in [the permissions documentation](https://backstage.io/docs/permissions/overview) and [the changelog](https://github.com/backstage/backstage/blob/master/plugins/permission-node/CHANGELOG.md#070). ### Migration: `jest` v29 @@ -64,8 +60,7 @@ Newly created Backstage repositories now use the stable version 6 of Migrating to the stable version of `react-router` is optional for the time being; Backstage has support for both versions. But if you want to do the same -for your existing repository, please follow [this -guide](https://backstage.io/docs/tutorials/react-router-stable-migration). +for your existing repository, please follow [this guide](https://backstage.io/docs/tutorials/react-router-stable-migration). Support for the beta version will be removed in a later release. ### Support for `__mocks__` and `__testUtils__` directories @@ -100,8 +95,7 @@ This release does not contain any security fixes. 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). +[keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). ## Links and References @@ -109,11 +103,9 @@ 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/) + [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) +- 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.7.0-changelog.md) - Backstage [Demos](https://backstage.io/demos), diff --git a/docs/local-dev/cli-overview.md b/docs/tooling/cli/01-overview.md similarity index 82% rename from docs/local-dev/cli-overview.md rename to docs/tooling/cli/01-overview.md index 4ab8bb21ac..78c4b2755f 100644 --- a/docs/local-dev/cli-overview.md +++ b/docs/tooling/cli/01-overview.md @@ -1,5 +1,5 @@ --- -id: cli-overview +id: overview title: Overview description: Overview of the Backstage CLI --- @@ -7,12 +7,12 @@ description: Overview of the Backstage CLI ## Introduction A goal of Backstage is to provide a delightful developer experience in and -around the project. Creating new [apps](../references/glossary.md#app) and -[plugins](../references/glossary.md#plugin) should be simple, iteration +around the project. Creating new [apps](../../references/glossary.md#app) and +[plugins](../../references/glossary.md#plugin) should be simple, iteration speed should be fast, and the overhead of maintaining custom tooling should be minimal. As a part of accomplishing this goal, Backstage provides its own build system and tooling, delivered primarily through the -[`@backstage/cli`](https://www.npmjs.com/package/@backstage/cli) [package](../references/glossary.md#package). When +[`@backstage/cli`](https://www.npmjs.com/package/@backstage/cli) [package](../../references/glossary.md#package). When creating an app using [`@backstage/create-app`](https://www.npmjs.com/package/@backstage/create-app), you receive a project that's already prepared with a typical setup and package @@ -23,8 +23,8 @@ Under the hood the CLI uses [Webpack](https://webpack.js.org/) for bundling, [Jest](https://jestjs.io/) for testing, and [eslint](https://eslint.org/) for linting. It also includes tooling for working within Backstage apps, for example for keeping the app up to date and verifying static configuration. For a more -in-depth look into the tooling, see the [build system](./cli-build-system.md) -page, and for a list of commands, see the [commands](./cli-commands.md) page. +in-depth look into the tooling, see the [build system](./02-build-system.md) +page, and for a list of commands, see the [commands](./03-commands.md) page. While the Backstage tooling is opinionated in how it works, it is also possible to use your own tooling either partially or fully. For example, the CLI provides diff --git a/docs/local-dev/cli-build-system.md b/docs/tooling/cli/02-build-system.md similarity index 99% rename from docs/local-dev/cli-build-system.md rename to docs/tooling/cli/02-build-system.md index ddcfa44cf5..bfdb21f45f 100644 --- a/docs/local-dev/cli-build-system.md +++ b/docs/tooling/cli/02-build-system.md @@ -1,5 +1,5 @@ --- -id: cli-build-system +id: build-system title: Build System description: A deep dive into the Backstage build system --- @@ -74,7 +74,7 @@ implemented in a typical Backstage app. ## Package Roles -> Package roles were introduced in March 2022. To migrate existing projects, see the [migration guide](../tutorials/package-role-migration.md). +> Package roles were introduced in March 2022. To migrate existing projects, see the [migration guide](../../tutorials/package-role-migration.md). The Backstage build system uses the concept of package roles in order to help keep configuration lean, provide utility and tooling, and enable optimizations. A package @@ -258,7 +258,7 @@ When building CommonJS or ESM output, the build commands will always use `src/index.ts` as the entrypoint. All non-relative modules imports are considered external, meaning the Rollup build will only compile the source code of the package itself. All import statements of external dependencies, even within the same -[monorepo](../references/glossary.md#monorepo), will stay intact. +[monorepo](../../references/glossary.md#monorepo), will stay intact. The build of the type definitions works quite differently. The entrypoint of the type definition build is the relative location of the package within the @@ -308,7 +308,7 @@ support for them instead. ### Frontend Production The frontend production bundling creates your typical web content -[bundle](../references/glossary.md#bundle), all contained within a single +[bundle](../../references/glossary.md#bundle), all contained within a single folder, ready for static serving. It is used when building packages with the `'frontend'` role, and unlike the development bundling there is no way to build a production bundle of an individual plugin. diff --git a/docs/local-dev/cli-commands.md b/docs/tooling/cli/03-commands.md similarity index 95% rename from docs/local-dev/cli-commands.md rename to docs/tooling/cli/03-commands.md index 173d616e61..234d0d04b7 100644 --- a/docs/local-dev/cli-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -1,5 +1,5 @@ --- -id: cli-commands +id: commands title: Commands description: Descriptions of all commands available in the CLI. --- @@ -102,7 +102,7 @@ Options: ## package start -Starts the package for local development. See the frontend and backend development parts in the build system [bundling](./cli-build-system.md#bundling) section for more details. +Starts the package for local development. See the frontend and backend development parts in the build system [bundling](./02-build-system.md#bundling) section for more details. ```text Usage: backstage-cli package start [options] @@ -119,7 +119,7 @@ Options: ## package build -Build an individual package based on its role. See the build system [building](./cli-build-system.md#building) and [bundling](./cli-build-system.md#bundling) sections for more details. +Build an individual package based on its role. See the build system [building](./02-build-system.md#building) and [bundling](./02-build-system.md#bundling) sections for more details. ```text Usage: backstage-cli package build [options] @@ -139,7 +139,7 @@ Options: Lint a package. In addition to the default `eslint` behavior, this command will include TypeScript files, treat warnings as errors, and default to linting the entire directory if no specific files are listed. For more information, see the -build system [linting](./cli-build-system.md#linting) section. +build system [linting](./02-build-system.md#linting) section. ```text Usage: backstage-cli package lint [options] @@ -165,7 +165,7 @@ a yarn workspaces monorepo by automatically creating one grouped configuration that includes all packages that have `backstage-cli test` in their package `test` script. -For more information about configuration overrides and editor support, see the [Jest Configuration section](./cli-build-system.md#jest-configuration) in the build system documentation. +For more information about configuration overrides and editor support, see the [Jest Configuration section](./02-build-system.md#jest-configuration) in the build system documentation. ```text Usage: backstage-cli package test [options] @@ -190,7 +190,7 @@ Delete cache directories This command should be added as `scripts.prepack` in all packages. It enables packaging- and publish-time overrides for fields inside `packages.json`. -For more details, see the build system [publishing](./cli-build-system.md#publishing) section. +For more details, see the build system [publishing](./02-build-system.md#publishing) section. ```text Usage: backstage-cli package prepack [options] @@ -369,8 +369,8 @@ Usage: backstage-cli build-workspace [options] ## create-github-app Creates a GitHub App in your GitHub organization. This is an alternative to -token-based [GitHub integration](../integrations/github/locations.md). See -[GitHub Apps for Backstage Authentication](../integrations/github/github-apps.md). +token-based [GitHub integration](../../integrations/github/locations.md). See +[GitHub Apps for Backstage Authentication](../../integrations/github/github-apps.md). Launches a browser to create the App through GitHub and saves the result as a YAML file that can be referenced in the GitHub integration configuration. diff --git a/docs/local-dev/debugging.md b/docs/tooling/local-dev/debugging.md similarity index 100% rename from docs/local-dev/debugging.md rename to docs/tooling/local-dev/debugging.md diff --git a/docs/local-dev/linking-local-packages.md b/docs/tooling/local-dev/linking-local-packages.md similarity index 100% rename from docs/local-dev/linking-local-packages.md rename to docs/tooling/local-dev/linking-local-packages.md diff --git a/docs/tutorials/journey.md b/docs/tutorials/journey.md deleted file mode 100644 index af78cbe597..0000000000 --- a/docs/tutorials/journey.md +++ /dev/null @@ -1,271 +0,0 @@ ---- -id: journey -title: Future developer journey -description: This document describes a possible journey of a future Backstage ---- - -> This document describes a possible journey of a **_future_** Backstage plugin -> developer as they build a plugin that touches many different aspects of a -> Backstage. The story invents many new things that are not part of Backstage -> today, but are things that I'm suggesting we should add as long term or north -> star goals. The idea is to discuss what parts of the story makes sense to aim -> for, and what we'd want to do differently or not at all. The "chapters" are -> numbered to make it a bit easier to comment on parts of the story. - -# The Protagonist - -Sam is an experienced developer that has worked with Backstage for a while, and -knows the best practices and tools available to build plugins. Sam also likes -music and wants to have a theme tune for every service in Backstage. - -# The End - -Sam built a Spotify plugin for Backstage that allows service owners to define a -theme tune for their service. The theme tune plays whenever a user visits the -service page in Backstage. The plugin is published to npm and available for any -organization to easily install and add to their Backstage installation. - -# 1. A New Plugin - -Sam chooses to develop this plugin in a standalone project and creates a new -plugin using `npx @backstage/cli new --select plugin`, which detects that it's not -being run in an existing project and therefore creates a separate plugin repo. - -Spinning up the frontend with `yarn start`, Sam goes to work with getting the -base functionality of a Spotify web player going. By installing a couple of -dependencies and whipping together a nice UI, the player is pretty much done. - -# 2. The Auth Menace - -Sam realizes users need to be authenticated towards the Spotify API to be able -to play music, and Backstage doesn't support Spotify login yet. Sam adds the -`@backstage/plugin-auth-backend` as local development middleware in the project, -and provides the necessary wrapping logic and configuration for the -`passport-spotify` strategy. The Spotify auth provider is now available in the -local development backend, and by adding a frontend `SpotifyAuth` Utility API -that implements the `OAuthApi` type, it's now working in the frontend too. - -```ts -const spotifyAuthApiRef = createApiRef({ - id: 'core.auth.spotify', -}); -``` - -Sam realizes that Spotify auth might be useful to others, and that it would be -more convenient if it was a part of the Backstage Core. After submitting and -merging a Pull Request with the additions to the -`@backstage/plugin-auth-backend` and `@backstage/core-plugin-api` packages, -Spotify auth is now available for everyone to use. Since the Backstage Core team -also adds it to the public demo server, Sam can now get rid of it in the local -setup and rely on the shared development auth providers instead. - -The only thing left now is making sure that users of the plugin provide Spotify -auth in the app. Sam ensures this by adding `spotifyAuthApiRef` to the plugin's -list of required APIs, as well as listing it in the requirements section in the -README. - -```md -## Requirements - -This plugin requires the following APIs to function: - -- `spotifyAuthApiRef` from `@@backstage/core-plugin-api@^1.1.0` -``` - -# 3. The Catalog Awakens - -Sam now has a working player and a method for users to log in to listen to -music, but the goal is to provide theme songs for services. Sam adds this -functionality by defining a new metadata annotation called -`sam.wise/spotify-track-id`. The annotation's value is a Spotify track ID and -can be defined in a component like this: - -```yaml -apiVersion: backstage.io/v1 -kind: Component -metadata: - name: my-component - annotations: - sam.wise/spotify-track-id: '4uLU6hMCjMI75M1A2tKUQC' -spec: - type: service -``` - -Sam creates a JSON schema that documents the annotation and allows it to be used -in validation and documentation for organizations that choose to adopt the -plugin. - -```json -{ - "sam.wise/spotify-track-id": { - "$id": "https://raw.githubusercontent.com/sam/backstage-spotify-theme/master/annotation.json#/sam.wise/spotify-track-id", - "type": "string", - "title": "Spotify Track Annotation", - "description": "Spotify track ID to associated with the entity", - "examples": ["4uLU6hMCjMI75M1A2tKUQC"] - } -} -``` - -# 4. The Rise of Widgets - -Sam also wraps the music player in an entity page widget. This allows anyone -that wants to use the plugin to add the player to any of their entity layout -templates, which will make it show up for every entity of that kind. - -```tsx -export const PlayerWidget = plugin.createEntityWidget({ - component: WebPlayer, - locations: ['header', 'card', 'footer'], - cardSize: [2, 4], -}); -``` - -The widget receives information about the entity in whose page it's being -embedded, which makes it simple to grab the track id from the annotations and -hook up the player. - -Sam also modifies the standalone plugin development setup to include this new -widget inside a basic entity page, adding it to a couple of different places -where users of the plugin may want to put the player, just to make sure they all -work. - -# 5. The First User - -At this point the only things that anyone that wants to use Sam's plugin needs -to do are to add -https://raw.githubusercontent.com/sam/backstage-spotify-theme/master/annotation.json#/sam.wise/spotify-track-id -to their catalog schema, import and add the `PlayerWidget` on the desired entity -template pages, and make sure they're providing Spotify auth. - -Sam soon sees the first "Used by" show up on GitHub, and feedback starts rolling -in. Users really like the plugin, and some a requesting the possibility to -select a theme tune when creating a new component. Sam jumps on the idea and -adds a new creation hook that is exported by the plugin. The hook can be -installed either in a single, all, or component templates that match a label. It -adds a field as a part of the component creation process with a nice search box -that allows users to search for a track that they want to use as the theme tune. - -# 6. Return to the Repo - -Sam is pretty content at this point, but would like to make it easier for users -to change the track after creation, preferable using the same search box that -was made for the creation form. By adding an edit button to the `PlayerWidget`, -and a nice empty state, Sam is able to provide the appropriate hooks in the GUI -to open up a search dialog. - -To save the selected track, Sam uses the `RepoApi` to suggest a change to the -entity definition file. This will create a Pull Request for organizations that -use GitHub, a Merge Request for users of GitLab, and so on. - -```ts -const repoApi = useApi(repoApiRef); -const alertApi = useApi(alertApiRef); - -const onSave = async () => { - const { url } = await repoApi.createChangeRequest({ - title: `Change theme tune to ${track.title} by ${track.artist}`, - changes: [ - { - path: entityYamlPath, - content: newEntityYamlContent, - }, - ], - }); - - alertApi.post({ message: `Requested change, ${url}` }); -}; -``` - -Now it's much simpler for users to change the theme tune, as they no longer need -to go look up a track ID and edit a YAML file. Instead, they can now stay inside -Backstage and search for the track and request the change from there. In -addition, the requested change can be reviewed by the regular process of each -organization. - -# 7. The User Strikes Back - -Sam's plugin is pretty popular at this point, and has been picked up and used by -many organizations. But some users start voicing concerns that they have too -many different hand-crafted annotations in their entity descriptions, and would -like to be able to avoid some of them. They really like the theme tunes though, -and wish they could keep them without having to put them in the entity -description, even if that means it won't go through the regular source control -review process. - -One day Sam receives a Pull Request for the plugin. It adds an option to use the -Database provided by `@backstage/backend-common` to store the track ID. It's all -packaged into a new backend plugin that will also extend the catalog backend -with schema and functionality to automatically load the value of the -`sam.wise/spotify-track-id` annotation from the backend plugin and database. The -backend plugin also extends the common GraphQL schema with a mutation that -updates the track ID in the database. - -On the frontend the Pull Request doesn't change much. It defines the save action -the was previously using the `RepoApi` in its own API. - -```ts -type ThemeTuneStorageApi = { - save(entity: Entity, trackId: string): Promise; -}; -``` - -The plugin also provides two different implementations of the API, one that uses -the old behavior of the `RepoApi`, and a new one that calls the `GraphQL` API. -The new API relies on the `IdentityApi` as a mechanism for authorizing changes, -instead of source control reviews. The `IdentityApi` provides a token that is -included in the request to the backend, which then must match the owner of the -component for which the user is trying to change the theme tune. - -> Author breaking the 4th wall here. I actually think every GraphQL request -> should include the ID token of the user, but invented a reason to include it -> here anyway. - -The API is selected based on a configuration parameter for the plugin, but -defaults to the original `RepoApi` behavior. - -```ts -if (config.getBoolean('storeTrackInDatabase')) { - return new GraphQLThemeTuneStore(graphqlClient, identityApi, alertApi); -} else { - return new RepoThemeTuneStore(repoApi, alertApi); -} -``` - -Sam is amazed by the pure awesomeness of this change, replies with a "👍" and -hits merge. - -# 8. Attack of the Clones - -Sam just released v1.8.4 of the plugin, and at this point it's so popular that a -couple of other plugins have started depending on the -`sam.wise/spotify-track-id` annotation. One such plugin being the -`spotify-album-art` plugin that can display the album art of the theme tune as -the background of the entity header. Sam thinks it's all pretty cool, but -doesn't like that the annotation that was once an internal concern of the plugin -is now becoming a standard in the community. - -In order to standardize the annotation in Backstage, Sam submits a Pull Request -to the Backstage Core repo. The request suggests a new well-known metadata -annotation called `spotify.com/track-id`, with the same schema definition as -Sam's label, and refers to Sam's own plugin and the `spotify-album-art` plugin -as existing usages. The Backstage maintainers merge the Pull Request, after -checking with the folks over at Spotify that they're cool with the annotation, -and faffing about over some minor grammar mistake in the annotation description. - -With the annotation now available inside Backstage Core, Sam releases v2 of the -plugin, which uses the new annotation. It can still consume the old annotation -for backwards compatibility, but new users of the plugin no longer need to add -the -https://raw.githubusercontent.com/sam/backstage-spotify-theme/master/annotation.json#/sam.wise/spotify-track-id -extension to their catalog schema, as it's now part of the core schema. The new -release of Sam's plugin specifies a dependency on Backstage with a minimum -version set to the same release as the one were the annotation was added to the -core schema. - -# 9. Revenge of the Sam - -Sam, now in full control of all theme tunes in Backstage, releases v2.0.1, which -switches all tracks to 4uLU6hMCjMI75M1A2tKUQC. Sam wanted to do something more -nefarious, but since Backstage sandboxes sensitive actions and is mostly -read-only with strict CSP, Sam's hands were tied. diff --git a/docs/tutorials/package-role-migration.md b/docs/tutorials/package-role-migration.md index db84defd91..dcd8a66ee6 100644 --- a/docs/tutorials/package-role-migration.md +++ b/docs/tutorials/package-role-migration.md @@ -10,7 +10,7 @@ information about the change can be found in the [original RFC](https://github.c Package roles are implemented through a well-known `"backstage"."role"` field in the `package.json` of each package. There are a handful of roles defined so far, and it -is not possible to use values outside the [set of predefined roles](../local-dev/cli-build-system.md#package-roles). +is not possible to use values outside the [set of predefined roles](../tooling/cli/02-build-system.md#package-roles). With roles in place in all packages, the Backstage CLI is able to automatically determine how to handle each package. For example, the different build commands @@ -55,7 +55,7 @@ yarn backstage-cli migrate package-roles The automatic detection is not perfect, so it is recommended to manually review the roles that were assigned to each package. -You can use the [package role definitions](../local-dev/cli-build-system.md#package-roles) as a reference. +You can use the [package role definitions](../tooling/cli/02-build-system.md#package-roles) as a reference. ### Step 2 - Migrate package scripts @@ -85,7 +85,7 @@ If you in the end do not want to use this exact script setup, it is still recomm ### Step 3 - Migrate package ESLint configurations -An area that has been simplified as part of the move to package roles is the ESLint configuration. Rather than having each package select which configuration they want (and getting it wrong), they now use a shared configuration factory that utilizes the package role. You can read more about the new configuration setup in the [build system documentation](../local-dev/cli-build-system.md#linting). +An area that has been simplified as part of the move to package roles is the ESLint configuration. Rather than having each package select which configuration they want (and getting it wrong), they now use a shared configuration factory that utilizes the package role. You can read more about the new configuration setup in the [build system documentation](../tooling/cli/02-build-system.md#linting). To migrate the ESLint configuration of all packages in your project, run the following command: @@ -97,7 +97,7 @@ This will migrate all existing `.eslintrc.js` that extend the old configuration ### Step 4 - Use `backstage-cli repo` -The Backstage CLI recently introduced a new `repo` command category, which houses commands that operate on an entire monorepo at once. These commands work particularly well once packages have been migrated to use roles, as that allows for some very effective optimizations. It is typically much faster to use these commands compared to using tools like `lerna`, as they're able to avoid the overhead of calling package scripts through `yarn` and can operate on multiple packages at once. You can read more about the `repo` command in the [CLI command documentation](../local-dev/cli-commands.md#repo-build). +The Backstage CLI recently introduced a new `repo` command category, which houses commands that operate on an entire monorepo at once. These commands work particularly well once packages have been migrated to use roles, as that allows for some very effective optimizations. It is typically much faster to use these commands compared to using tools like `lerna`, as they're able to avoid the overhead of calling package scripts through `yarn` and can operate on multiple packages at once. You can read more about the `repo` command in the [CLI command documentation](../tooling/cli/03-commands.md#repo-build). The way to execute this step of the migration is not as well defined as the previous steps, as it depends on what your development and CI/CD setup looks like. Look for the following patterns to replace in your root `package.json` as well as CI/CD setup: diff --git a/docs/tutorials/setup-opentelemetry.md b/docs/tutorials/setup-opentelemetry.md index 976ba4ccfb..30dde79db8 100644 --- a/docs/tutorials/setup-opentelemetry.md +++ b/docs/tutorials/setup-opentelemetry.md @@ -6,42 +6,37 @@ description: Tutorial to setup OpenTelemetry metrics and traces exporters in Bac Backstage uses [OpenTelemetery](https://opentelemetry.io/) to instrument its components by reporting traces and metrics. -This tutorial shows how to setup exporters in your Backstage backend package. For demonstration purposes we will use the simple console exporters. +This tutorial shows how to setup exporters in your Backstage backend package. For demonstration purposes we will use a Prometheus exporter, but you can adjust your solution to use another one that suits your needs; see for example the article on [OTLP exporters](https://opentelemetry.io/docs/instrumentation/js/exporters/). ## Install dependencies We will use the OpenTelemetry Node SDK and the `auto-instrumentations-node` packages. -Backstage packages, such as the catalog, uses the OpenTelemetry API to send custom traces and metrics. +Backstage packages, such as the catalog, use the OpenTelemetry API to send custom traces and metrics. The `auto-instrumentations-node` will automatically create spans for code called in libraries like Express. ```bash -yarn --cwd packages/backend add @opentelemetry/sdk-node \ +yarn --cwd packages/backend add \ + @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ - @opentelemetry/sdk-metrics \ - @opentelemetry/sdk-trace-node + @opentelemetry/exporter-prometheus ``` ## Configure -In your `packages/backend` folder, create an `instrumentation.js` file. +In your `packages/backend/src` folder, create an `instrumentation.js` file. -```typescript +```typescript title="in packages/backend/src/instrumentation.js" const { NodeSDK } = require('@opentelemetry/sdk-node'); -const { ConsoleSpanExporter } = require('@opentelemetry/sdk-trace-node'); const { getNodeAutoInstrumentations, } = require('@opentelemetry/auto-instrumentations-node'); -const { - PeriodicExportingMetricReader, - ConsoleMetricExporter, -} = require('@opentelemetry/sdk-metrics'); +const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); +const prometheus = new PrometheusExporter(); const sdk = new NodeSDK({ - traceExporter: new ConsoleSpanExporter(), - metricReader: new PeriodicExportingMetricReader({ - exporter: new ConsoleMetricExporter(), - }), + // You can add a traceExporter field here too + metricReader: prometheus, instrumentations: [getNodeAutoInstrumentations()], }); @@ -51,43 +46,40 @@ sdk.start(); You probably won't need all of the instrumentation inside `getNodeAutoInstrumentations()` so make sure to check the [documentation](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) and tweak it properly. -It's important to setup the NodeSDK and the automatic instrumentation **before** importing any library. +## Local Development Setup -This is why we will use the nodejs [`--require`](https://nodejs.org/api/cli.html#-r---require-module) -flag when we start up the application. +It's important to setup the NodeSDK and the automatic instrumentation **before** +importing any library. This is why we will use the nodejs +[`--require`](https://nodejs.org/api/cli.html#-r---require-module) flag when we +start up the application. -In your `Dockerfile` add the `--require` flag which points to the `instrumentation.js` file +For local development, you can add the required flag in your `packages/backend/package.json`. + +```json title="packages/backend/package.json" +"scripts": { + "start": "backstage-cli package start --require ./src/instrumentation.js", + ... +``` + +You can now start your Backstage instance as usual, using `yarn dev`. + +## Production Setup + +In your `Dockerfile`, copy `instrumentation.js` file into the root of the working directory. ```Dockerfile +COPY --chown=${NOT_ROOT_USER}:${NOT_ROOT_USER} packages/backend/src/instrumentation.js ./ +``` -# We need the instrumentation file inside the Docker image so we can use it with --require -// highlight-add-next-line -COPY --chown=node:node packages/backend/instrumentation.js ./ +And then add the `--require` flag that points to the file to the CMD array. +```Dockerfile // highlight-remove-next-line CMD ["node", "packages/backend", "--config", "app-config.yaml"] // highlight-add-next-line CMD ["node", "--require", "./instrumentation.js", "packages/backend", "--config", "app-config.yaml"] ``` -## Run Backstage - -The above configuration will only work in production once your start a Docker container from the image. - -To be able to test locally you can import the `./instrumentation.js` file at the top (before all imports) of your backend `index.ts` file - -```ts -import '../instrumentation.js' -// Other imports -... -``` - -You can now start your Backstage instance as usual, using `yarn dev`. - -When the backend is started, you should see in your console traces and metrics emitted by OpenTelemetry. - -Of course in production you probably won't use the console exporters but instead send traces and metrics to an OpenTelemetry Collector or other exporter using [OTLP exporters](https://opentelemetry.io/docs/instrumentation/js/exporters/). - If you need to disable/configure some OpenTelemetry feature there are lots of [environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) which you can tweak. ## References diff --git a/docs/tutorials/using-backstage-proxy-within-plugin.md b/docs/tutorials/using-backstage-proxy-within-plugin.md index 3002eb1aff..1abfe9e5b6 100644 --- a/docs/tutorials/using-backstage-proxy-within-plugin.md +++ b/docs/tutorials/using-backstage-proxy-within-plugin.md @@ -125,7 +125,7 @@ export class MyAwesomeApiClient implements MyAwesomeApi { private async fetch(input: string, init?: RequestInit): Promise { // As configured previously for the backend proxy - const proxyUri = '${await this.discoveryApi.getBaseUrl('proxy')}/'; + const proxyUri = `${await this.discoveryApi.getBaseUrl('proxy')}/`; const resp = await fetch(`${proxyUri}${input}`, init); if (!resp.ok) throw new Error(resp); diff --git a/microsite/blog/2021-06-22-spotify-backstage-is-growing.mdx b/microsite/blog/2021-06-22-spotify-backstage-is-growing.mdx index 6cae5c907e..308effaeab 100644 --- a/microsite/blog/2021-06-22-spotify-backstage-is-growing.mdx +++ b/microsite/blog/2021-06-22-spotify-backstage-is-growing.mdx @@ -66,9 +66,9 @@ Speaking of reviewers and maintainers… ## Adding reviewers and maintainers -[![GitHub logo](assets/21-06-22/gh-reviewers.png)](https://github.com/backstage/backstage/blob/master/GOVERNANCE.md#reviewers) +[![GitHub logo](assets/21-06-22/gh-reviewers.png)](https://github.com/backstage/community/blob/main/GOVERNANCE.md#reviewers) -We have introduced [reviewers](https://github.com/backstage/backstage/blob/master/GOVERNANCE.md#reviewers) to the project! By adding this new role, we’ve expanded the number of people who are permitted to approve and merge pull requests. This will offload some of the review work from the maintainers, simplifying and speeding up the review process for contributors. +We have introduced [reviewers](https://github.com/backstage/community/blob/main/GOVERNANCE.md#reviewers) to the project! By adding this new role, we’ve expanded the number of people who are permitted to approve and merge pull requests. This will offload some of the review work from the maintainers, simplifying and speeding up the review process for contributors. Of course, with these new efforts, we expect even more companies to adopt Backstage, which means the platform will continue to grow, and the number of PRs will continue to grow with it. As that happens, we hope to add to both the maintainer and reviewer teams in the future. diff --git a/microsite/blog/2023-04-26-kubecon-eu-2023.mdx b/microsite/blog/2023-04-26-kubecon-eu-2023.mdx index 7ee549c088..8f369c2d14 100644 --- a/microsite/blog/2023-04-26-kubecon-eu-2023.mdx +++ b/microsite/blog/2023-04-26-kubecon-eu-2023.mdx @@ -21,7 +21,7 @@ On Tuesday the Backstage maintainers hosted a jam-packed project meeting. The co ![Patrik and Ben onstage for the State of Backstage talk](assets/2023-04-26/IMG_0120.png) -Core maintainers [Ben Lambert](https://github.com/benjdlambert) and [Patrik Oldsberg](https://github.com/Rugvip) took center stage on Wednesday for the Backstage Maintainer Track: State of Backstage in 2023 talk. Backstage has officially hit over 1,000 adopters and 1,000 contributors – so it’s apt timing to modernize the governance model for the project. Taking pointers from the [CNCF Contributor Ladder Governance Template](https://contribute.cncf.io/maintainers/templates/), a new [Backstage Governance Model](https://github.com/backstage/backstage/blob/master/GOVERNANCE.md) is now in effect! Patrik walked us through the new ladder model which introduces a number of changes, one being the addition of [project area maintainers](https://github.com/backstage/backstage/blob/master/GOVERNANCE.md#project-area-maintainer). This role lets members of the community take increased ownership over a specific area of interest, like Catalog, Discoverability, TechDocs, Helm Charts, and Kubernetes. New project areas that will be added include Permissions and Software Templates. New project areas can be proposed by nominating a project area maintainer for the area. The new model also adds an organization member role for contributors who want to take a more active role in the Backstage community. You can open an issue to become an organization member [here](https://github.com/backstage/community/issues/new/choose). +Core maintainers [Ben Lambert](https://github.com/benjdlambert) and [Patrik Oldsberg](https://github.com/Rugvip) took center stage on Wednesday for the Backstage Maintainer Track: State of Backstage in 2023 talk. Backstage has officially hit over 1,000 adopters and 1,000 contributors – so it’s apt timing to modernize the governance model for the project. Taking pointers from the [CNCF Contributor Ladder Governance Template](https://contribute.cncf.io/maintainers/templates/), a new [Backstage Governance Model](https://github.com/backstage/community/blob/main/GOVERNANCE.md) is now in effect! Patrik walked us through the new ladder model which introduces a number of changes, one being the addition of [project area maintainers](https://github.com/backstage/community/blob/main/GOVERNANCE.md#project-area-maintainer). This role lets members of the community take increased ownership over a specific area of interest, like Catalog, Discoverability, TechDocs, Helm Charts, and Kubernetes. New project areas that will be added include Permissions and Software Templates. New project areas can be proposed by nominating a project area maintainer for the area. The new model also adds an organization member role for contributors who want to take a more active role in the Backstage community. You can open an issue to become an organization member [here](https://github.com/backstage/community/issues/new/choose). ![Contributor ladder](assets/2023-04-26/contributor_ladder.png) diff --git a/microsite/blog/2024-04-19-community-plugins.mdx b/microsite/blog/2024-04-19-community-plugins.mdx index bb8b9c2313..49d1765bce 100644 --- a/microsite/blog/2024-04-19-community-plugins.mdx +++ b/microsite/blog/2024-04-19-community-plugins.mdx @@ -14,7 +14,7 @@ For those who depended on these plugins, migrating is as simple as `yarn backsta ## The community plugins repo -Some of you who have been around a while, or have seen our [Maintainer Track talks](https://www.youtube.com/watch?v=ONMBYnhxnNU) at KubeCon, might have seen [this RFC](https://github.com/backstage/backstage/issues/20266) which outlines some issues with the scale of the `backstage/backstage` monorepo, and us as maintainers being the de facto owners of all plugins without a [project area](https://github.com/backstage/backstage/blob/master/GOVERNANCE.md#project-area) or [plugin maintainer](https://github.com/backstage/backstage/blob/master/GOVERNANCE.md#project-area-maintainer). +Some of you who have been around a while, or have seen our [Maintainer Track talks](https://www.youtube.com/watch?v=ONMBYnhxnNU) at KubeCon, might have seen [this RFC](https://github.com/backstage/backstage/issues/20266) which outlines some issues with the scale of the `backstage/backstage` monorepo, and us as maintainers being the de facto owners of all plugins without a [project area](https://github.com/backstage/community/blob/main/GOVERNANCE.md#project-area) or [plugin maintainer](https://github.com/backstage/community/blob/main/GOVERNANCE.md#project-area-maintainer). There was some great discussion in this issue, and some great ideas. One of the ideas was to create a dedicated home for community plugins, with all the burden of release tooling and workspace tooling already set up, which is a pretty big barrier for people wanting to create plugins for Backstage in their own organization or personal account. These plugins would then have the ability to release independently of the main monorepo, and have their own release cadence, which is something that we've been looking at exploring for a while. diff --git a/microsite/data/plugins/airbrake.yaml b/microsite/data/plugins/airbrake.yaml index 7f946597ef..8facf13185 100644 --- a/microsite/data/plugins/airbrake.yaml +++ b/microsite/data/plugins/airbrake.yaml @@ -4,7 +4,7 @@ author: Simply Business authorUrl: https://github.com/simplybusiness/ category: Monitoring description: Access Airbrake error monitoring and other integrations from within Backstage -documentation: https://github.com/backstage/backstage/blob/master/plugins/airbrake +documentation: https://github.com/backstage/community-plugins/tree/main/workspaces/airbrake/plugins/airbrake iconUrl: https://wp-assets.airbrake.io/wp-content/uploads/2020/10/05222904/Square-white-A-on-Orange.png npmPackageName: '@backstage/plugin-airbrake' addedDate: '2022-01-10' diff --git a/microsite/data/plugins/analytics-module-ga.yaml b/microsite/data/plugins/analytics-module-ga.yaml index 54dea6454a..968b1831ab 100644 --- a/microsite/data/plugins/analytics-module-ga.yaml +++ b/microsite/data/plugins/analytics-module-ga.yaml @@ -4,7 +4,7 @@ author: Spotify authorUrl: https://github.com/spotify category: Monitoring description: Track usage of your Backstage instance using Google Analytics. -documentation: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/analytics/plugins/analytics-module-ga/README.md iconUrl: /img/ga-icon.png npmPackageName: '@backstage/plugin-analytics-module-ga' addedDate: '2021-10-07' diff --git a/microsite/data/plugins/apollo-explorer.yaml b/microsite/data/plugins/apollo-explorer.yaml index 98008e3fc0..2b0f834f92 100644 --- a/microsite/data/plugins/apollo-explorer.yaml +++ b/microsite/data/plugins/apollo-explorer.yaml @@ -1,10 +1,10 @@ --- title: Apollo Explorer -author: unredundant -authorUrl: https://github.com/unredundant +author: brizzbuzz +authorUrl: https://github.com/brizzbuzz category: Debugging description: Integrates Apollo Explorer graphs as a tool to browse GraphQL API endpoints inside Backstage. -documentation: https://github.com/backstage/backstage/blob/master/plugins/apollo-explorer/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/apollo-explorer/plugins/apollo-explorer/README.md iconUrl: /img/apollo-explorer.png npmPackageName: '@backstage/plugin-apollo-explorer' addedDate: '2022-07-20' diff --git a/microsite/data/plugins/azure-pipelines.yaml b/microsite/data/plugins/azure-pipelines.yaml index 5b719a4248..e0e3534fdb 100644 --- a/microsite/data/plugins/azure-pipelines.yaml +++ b/microsite/data/plugins/azure-pipelines.yaml @@ -4,7 +4,7 @@ author: Keyloop authorUrl: https://keyloop.com/ category: CI/CD description: Easily view your Azure Pipelines within the Software Catalog -documentation: https://github.com/backstage/backstage/blob/master/plugins/azure-devops/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/azure-devops/plugins/azure-devops/README.md iconUrl: /img/azure-pipelines.svg npmPackageName: '@backstage/plugin-azure-devops' addedDate: '2021-12-22' diff --git a/microsite/data/plugins/badges.yaml b/microsite/data/plugins/badges.yaml index 86d16ab547..789aaf155d 100644 --- a/microsite/data/plugins/badges.yaml +++ b/microsite/data/plugins/badges.yaml @@ -4,7 +4,7 @@ author: Andreas Stenius authorUrl: https://github.com/backstage/community category: Discovery description: The badges plugin offers a set of badges that can be used outside of Backstage, showing information related to data from the catalog. -documentation: https://github.com/backstage/backstage/blob/master/plugins/badges/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/badges/plugins/badges/README.md iconUrl: /img/badges.svg npmPackageName: '@backstage/plugin-badges' addedDate: '2021-09-29' diff --git a/microsite/data/plugins/bazaar.yaml b/microsite/data/plugins/bazaar.yaml index ce3a4d5dfc..1130822e77 100644 --- a/microsite/data/plugins/bazaar.yaml +++ b/microsite/data/plugins/bazaar.yaml @@ -3,7 +3,7 @@ author: Axis Communications AB authorUrl: https://www.axis.com category: Discovery description: A marketplace where engineers can propose projects suitable for inner sourcing -documentation: https://github.com/backstage/backstage/blob/master/plugins/bazaar/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/bazaar/plugins/bazaar/README.md iconUrl: /img/bazaar.svg npmPackageName: '@backstage/plugin-bazaar' addedDate: '2022-01-11' diff --git a/microsite/data/plugins/betterscan.yaml b/microsite/data/plugins/betterscan.yaml index 92d1eaa7b2..852ae0081c 100644 --- a/microsite/data/plugins/betterscan.yaml +++ b/microsite/data/plugins/betterscan.yaml @@ -4,7 +4,7 @@ author: Marcin Kozlowski authorUrl: https://betterscan.io category: Security description: View security scanned vulnerabilities in Code and Cloud scanned using Open Source and proprietary scanners directly in Backstage. -documentation: https://github.com/marcinguy/betterscan-ce +documentation: https://www.npmjs.com/package/@marcinguy/backstage-plugin-betterscan iconUrl: https://uploads-ssl.webflow.com/6339e3b81867539b5fe2498d/633a1643dcb06d3029867161_g4.svg npmPackageName: '@marcinguy/backstage-plugin-betterscan' addedDate: '2022-12-08' diff --git a/microsite/data/plugins/bitrise.yaml b/microsite/data/plugins/bitrise.yaml index 5e5b74f3ad..5cbfe5aabf 100644 --- a/microsite/data/plugins/bitrise.yaml +++ b/microsite/data/plugins/bitrise.yaml @@ -4,7 +4,7 @@ author: SDA SE authorUrl: https://sda.se/ category: CI/CD description: View Bitrise builds and download the build artifacts within Backstage. -documentation: https://github.com/backstage/backstage/blob/master/plugins/bitrise/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/bitrise/plugins/bitrise/README.md iconUrl: https://avatars.githubusercontent.com/u/7174390?s=400&v=4 npmPackageName: '@backstage/plugin-bitrise' addedDate: '2021-03-01' diff --git a/microsite/data/plugins/digital.ai-deploy.yaml b/microsite/data/plugins/digital.ai-deploy.yaml new file mode 100644 index 0000000000..6077f59fa7 --- /dev/null +++ b/microsite/data/plugins/digital.ai-deploy.yaml @@ -0,0 +1,13 @@ +--- +title: Digital.ai Deploy +author: digital.ai +authorUrl: https://digital.ai/ +category: CI/CD +description: The plugin offers integration with Digital.ai Deploy and backstage components and services. It provide access to deployments and reports. +documentation: https://docs.digital.ai/bundle/devops-deploy-version-v.24.1/page/deploy/concept/xl-deploy-backstage-overview.html +iconUrl: /img/digital.ai-deploy.svg +npmPackageName: '@digital.ai/plugin-dai-deploy' +tags: + - ci + - cd +addedDate: '2024-05-06' diff --git a/microsite/data/plugins/firehydrant.yaml b/microsite/data/plugins/firehydrant.yaml index 8a1f122051..7aa00675b4 100644 --- a/microsite/data/plugins/firehydrant.yaml +++ b/microsite/data/plugins/firehydrant.yaml @@ -4,7 +4,7 @@ author: FireHydrant authorUrl: https://firehydrant.io/ category: Monitoring description: View service incidents information from FireHydrant, such as active incidents and incident metrics, directly within Backstage. -documentation: https://github.com/backstage/backstage/blob/master/plugins/firehydrant/README.md -iconUrl: https://raw.githubusercontent.com/backstage/backstage/master/plugins/firehydrant/doc/firehydrant_logo.png +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/firehydrant/plugins/firehydrant/README.md +iconUrl: https://github.com/backstage/community-plugins/blob/main/workspaces/firehydrant/plugins/firehydrant/doc/firehydrant_logo.png npmPackageName: '@backstage/plugin-firehydrant' addedDate: '2021-08-18' diff --git a/microsite/data/plugins/fossa.yaml b/microsite/data/plugins/fossa.yaml index e46228a848..a1a66eb7d6 100644 --- a/microsite/data/plugins/fossa.yaml +++ b/microsite/data/plugins/fossa.yaml @@ -4,7 +4,7 @@ author: SDA SE authorUrl: https://sda.se/ category: Quality description: View FOSSA license compliance of your components in Backstage. -documentation: https://github.com/backstage/backstage/blob/master/plugins/fossa/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/fossa/plugins/fossa/README.md iconUrl: https://avatars0.githubusercontent.com/u/9543448?s=400&v=4 npmPackageName: '@backstage/plugin-fossa' addedDate: '2020-12-10' diff --git a/microsite/data/plugins/github-codespaces.yaml b/microsite/data/plugins/github-codespaces.yaml index d846235bd6..043be3200b 100644 --- a/microsite/data/plugins/github-codespaces.yaml +++ b/microsite/data/plugins/github-codespaces.yaml @@ -5,7 +5,7 @@ authorUrl: https://github.com/adityasinghal26 category: Development description: Integrates GitHub Codespaces for a Backstage component with the Authenticated User. documentation: https://github.com/adityasinghal26/backstage-plugins/tree/main/plugins/github-codespaces -iconUrl: https://github.com/adityasinghal26/backstage-plugins/blob/00c9c00ba9acc3135014d6454ccf04f573195eef/plugins/github-codespaces/images/GitHubLogo.png +iconUrl: https://github.com/adityasinghal26/backstage-plugins/blob/main/plugins/github-codespaces/images/GitHubLogo.png npmPackageName: '@adityasinghal26/plugin-github-codespaces' tags: - github diff --git a/microsite/data/plugins/graphql-catalog.yaml b/microsite/data/plugins/graphql-catalog.yaml new file mode 100644 index 0000000000..9255f475e7 --- /dev/null +++ b/microsite/data/plugins/graphql-catalog.yaml @@ -0,0 +1,14 @@ +--- +title: GraphQL Catalog +author: Frontside Software +authorUrl: https://frontside.com/ +category: Discovery +description: Adds the GraphQL Endpoint to Backstage Catalog as a plugin. +documentation: https://github.com/thefrontside/playhouse/blob/main/plugins/graphql-backend/README.md +iconUrl: https://raw.githubusercontent.com/thefrontside/frontside.com/production/legacy/src/img/frontside-logo.png +npmPackageName: '@frontside/backstage-plugin-graphql-backend' +tags: + - graphql + - catalog + - graphql-catalog +addedDate: '2024-05-01' diff --git a/microsite/data/plugins/humanitec.yaml b/microsite/data/plugins/humanitec.yaml index 7265b9d917..a94ca431e6 100644 --- a/microsite/data/plugins/humanitec.yaml +++ b/microsite/data/plugins/humanitec.yaml @@ -1,12 +1,12 @@ --- title: Humanitec Platform Orchestrator -author: Frontside -authorUrl: 'https://frontside.com' +author: Humanitec +authorUrl: 'https://humanitec.com' category: Deployment # A single category e.g. CI, Machine Learning, Services, Monitoring description: | Show workloads, environments and resources deployed by Humanitec Platform Orchestrator. Plugin includes an Entity ComponentCard, Backend API route and scaffolder actions. -documentation: https://github.com/thefrontside/playhouse/tree/main/plugins/humanitec +documentation: https://github.com/humanitec/humanitec-backstage-plugins iconUrl: /img/humanitec-logo.png -npmPackageName: '@frontside/backstage-plugin-humanitec' +npmPackageName: '@humanitec/backstage-plugin' addedDate: '2022-06-22' diff --git a/microsite/data/plugins/ibm-apic-backend.yaml b/microsite/data/plugins/ibm-apic-backend.yaml index 9228524a2d..dcb41a1cef 100644 --- a/microsite/data/plugins/ibm-apic-backend.yaml +++ b/microsite/data/plugins/ibm-apic-backend.yaml @@ -5,7 +5,7 @@ authorUrl: https://croz.net/?utm_source=backstage.io&utm_medium=marketplace&utm_ category: API Management description: Bring IBM APIC to Backstage. documentation: https://github.com/croz-ltd/apic-backend-plugin?utm_source=backstage.io&utm_medium=marketplace&utm_campaign=backstage-ibm-apic-backend -iconUrl: https://croz.net/wp-content/uploads/2024/02/croz_large-o.png +iconUrl: https://croz.net/app/uploads/2024/05/apple-touch-icon.png npmPackageName: '@croz/plugin-ibm-apic-backend' tags: - openapic diff --git a/microsite/data/plugins/linguist.yaml b/microsite/data/plugins/linguist.yaml index d76936391c..fb8e88b747 100644 --- a/microsite/data/plugins/linguist.yaml +++ b/microsite/data/plugins/linguist.yaml @@ -4,7 +4,7 @@ author: Keyloop authorUrl: https://keyloop.com/ category: Metadata description: View the programming language break down for your entities within the Software Catalog -documentation: https://github.com/backstage/backstage/blob/master/plugins/linguist/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/linguist/plugins/linguist/README.md iconUrl: /img/linguist.svg npmPackageName: '@backstage/plugin-linguist' addedDate: '2023-06-17' diff --git a/microsite/data/plugins/newrelic-dashboard.yaml b/microsite/data/plugins/newrelic-dashboard.yaml index 420c506b35..e53285cca7 100644 --- a/microsite/data/plugins/newrelic-dashboard.yaml +++ b/microsite/data/plugins/newrelic-dashboard.yaml @@ -4,7 +4,7 @@ author: '@mufaddal7' authorUrl: https://github.com/mufaddal7 category: Monitoring description: Easily view your New Relic Dashboards in Backstage, via real-time snapshots of your dashboards -documentation: https://github.com/backstage/community-plugins/tree/main/workspaces/newrelic-dashboard/plugins/newrelic-dashboard +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/newrelic/plugins/newrelic-dashboard/README.md iconUrl: https://newrelic.com/themes/custom/erno/assets/mediakit/new_relic_logo_vertical_white.svg npmPackageName: '@backstage-community/plugin-newrelic-dashboard' tags: diff --git a/microsite/data/plugins/octopus-deploy.yaml b/microsite/data/plugins/octopus-deploy.yaml index 1ed7439695..cfc5e2c9e5 100644 --- a/microsite/data/plugins/octopus-deploy.yaml +++ b/microsite/data/plugins/octopus-deploy.yaml @@ -4,7 +4,7 @@ author: jmezach authorUrl: https://jmezach.github.io/ category: CI/CD description: Easily view your Octopus Deploy releases within the Software Catalog -documentation: https://github.com/backstage/backstage/blob/master/plugins/octopus-deploy/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/octopus-deploy/plugins/octopus-deploy/README.md iconUrl: /img/octopus-deploy.svg npmPackageName: '@backstage/plugin-octopus-deploy' addedDate: '2023-02-24' diff --git a/microsite/data/plugins/opencost.yaml b/microsite/data/plugins/opencost.yaml index 950b0606a7..95973e3b0c 100644 --- a/microsite/data/plugins/opencost.yaml +++ b/microsite/data/plugins/opencost.yaml @@ -4,7 +4,7 @@ author: Matt Ray authorUrl: https://opencost.io category: Monitoring description: OpenCost provides cloud cost monitoring for your cloud native environments. -documentation: https://github.com/backstage/backstage/blob/master/plugins/opencost/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/opencost/plugins/opencost/README.md iconUrl: /img/opencost.png npmPackageName: '@backstage/plugin-opencost' addedDate: '2023-10-26' diff --git a/microsite/data/plugins/puppetdb.yaml b/microsite/data/plugins/puppetdb.yaml index d3b6bd2bcb..650d8318d3 100644 --- a/microsite/data/plugins/puppetdb.yaml +++ b/microsite/data/plugins/puppetdb.yaml @@ -4,7 +4,7 @@ author: TDabasinskas authorUrl: https://github.com/tdabasinskas category: Configuration Management description: Visualize resource information and Puppet facts from PuppetDB. -documentation: https://github.com/backstage/backstage/blob/master/plugins/puppetdb/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/puppetdb/plugins/puppetdb/README.md iconUrl: /img/puppet.png npmPackageName: '@backstage/plugin-puppetdb' tags: diff --git a/microsite/data/plugins/shortcuts.yaml b/microsite/data/plugins/shortcuts.yaml index 7c3f2c6d56..b420e28e2f 100644 --- a/microsite/data/plugins/shortcuts.yaml +++ b/microsite/data/plugins/shortcuts.yaml @@ -4,7 +4,7 @@ author: Spotify authorUrl: https://github.com/spotify category: Utility description: The shortcuts plugin allows a user to have easy access to pages within a Backstage app by storing them as "shortcuts" in the Sidebar. -documentation: https://github.com/backstage/backstage/blob/master/plugins/shortcuts/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/shortcuts/plugins/shortcuts/README.md iconUrl: /img/shortcuts.svg npmPackageName: '@backstage/plugin-shortcuts' addedDate: '2021-10-06' diff --git a/microsite/data/plugins/sonarqube.yaml b/microsite/data/plugins/sonarqube.yaml index f24441c46e..72c662e2fa 100644 --- a/microsite/data/plugins/sonarqube.yaml +++ b/microsite/data/plugins/sonarqube.yaml @@ -4,7 +4,7 @@ author: SDA SE authorUrl: https://sda.se/ category: Quality description: Components to display code quality metrics from SonarCloud and SonarQube. -documentation: https://github.com/backstage/backstage/blob/master/plugins/sonarqube/README.md +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/sonarqube/plugins/sonarqube/README.md iconUrl: /img/sonarqube-icon.svg npmPackageName: '@backstage/plugin-sonarqube' addedDate: '2020-11-03' diff --git a/microsite/data/plugins/stack-overflow.yaml b/microsite/data/plugins/stack-overflow.yaml index a5e2122f8a..b058ce90fe 100644 --- a/microsite/data/plugins/stack-overflow.yaml +++ b/microsite/data/plugins/stack-overflow.yaml @@ -4,7 +4,7 @@ author: Spotify authorUrl: https://github.com/spotify category: Discovery description: Provides Stack Overflow specific functionality that can be used in different ways (e.g. for homepage and search) to compose your Backstage App. -documentation: https://github.com/backstage/backstage/blob/master/plugins/stack-overflow +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/stack-overflow/plugins/stack-overflow/README.md iconUrl: /img/stack-overflow-logo.svg npmPackageName: '@backstage/plugin-stack-overflow' addedDate: '2022-06-14' diff --git a/microsite/docusaurus.config.js b/microsite/docusaurus.config.js deleted file mode 100644 index 1866deda5c..0000000000 --- a/microsite/docusaurus.config.js +++ /dev/null @@ -1,349 +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. - */ - -// @ts-check - -/** @type{import('prism-react-renderer').PrismTheme} **/ -// @ts-ignore -const prismTheme = require('prism-react-renderer/themes/vsDark'); -prismTheme.plain.backgroundColor = '#232323'; - -/** @type {import('@docusaurus/types').Config} */ -module.exports = { - title: 'Backstage Software Catalog and Developer Platform', - tagline: 'An open source framework for building developer portals', - url: 'https://backstage.io', - baseUrl: '/', - organizationName: 'Spotify', - projectName: 'backstage', - scripts: [ - 'https://buttons.github.io/buttons.js', - 'https://unpkg.com/medium-zoom@1.0.6/dist/medium-zoom.min.js', - '/js/medium-zoom.js', - '/js/dismissable-banner.js', - '/js/scroll-nav-to-view-in-docs.js', - ], - stylesheets: [ - 'https://fonts.googleapis.com/css?family=IBM+Plex+Mono:500,700&display=swap', - ], - favicon: 'img/favicon.ico', - customFields: { - fossWebsite: 'https://spotify.github.io/', - repoUrl: 'https://github.com/backstage/backstage', - }, - onBrokenLinks: 'log', - onBrokenMarkdownLinks: 'log', - presets: [ - [ - '@docusaurus/preset-classic', - /** @type {import('@docusaurus/preset-classic').Options} */ - { - docs: { - editUrl: 'https://github.com/backstage/backstage/edit/master/docs/', - path: '../docs', - sidebarPath: 'sidebars.json', - }, - blog: { - path: 'blog', - }, - theme: { - customCss: 'src/theme/customTheme.scss', - }, - gtag: { - trackingID: 'G-KSEVGGNCJW', - }, - }, - ], - ], - markdown: { - preprocessor({ fileContent }) { - // Replace all HTML comments with empty strings as these are not supported by MDXv2. - return fileContent.replace(//gs, ''); - }, - format: 'detect', - }, - webpack: { - jsLoader: isServer => ({ - loader: require.resolve('swc-loader'), - options: { - jsc: { - parser: { - syntax: 'typescript', - tsx: true, - }, - target: 'es2017', - }, - module: { - type: isServer ? 'commonjs' : 'es6', - }, - }, - }), - }, - plugins: [ - 'docusaurus-plugin-sass', - () => ({ - name: 'yaml-loader', - configureWebpack() { - return { - module: { - rules: [ - { - test: /\.ya?ml$/, - use: 'yaml-loader', - }, - ], - }, - }; - }, - }), - [ - '@docusaurus/plugin-client-redirects', - { - redirects: [ - { - from: '/docs', - to: '/docs/overview/what-is-backstage', - }, - { - from: '/docs/features/software-catalog/software-catalog-overview', - to: '/docs/features/software-catalog/', - }, - { - from: '/docs/features/software-templates/software-templates-index', - to: '/docs/features/software-templates/', - }, - { - from: '/docs/features/techdocs/techdocs-overview', - to: '/docs/features/techdocs/', - }, - { - from: '/docs/features/kubernetes/overview', - to: '/docs/features/kubernetes/', - }, - { - from: '/docs/features/search/search-overview', - to: '/docs/features/search/', - }, - { - from: '/docs/getting-started/running-backstage-locally', - to: '/docs/getting-started/', - }, - { - from: '/docs/features/software-templates/testing-scaffolder-alpha', - to: '/docs/features/software-templates/migrating-to-rjsf-v5', - }, - { - from: '/docs/auth/glossary', - to: '/docs/references/glossary', - }, - { - from: '/docs/overview/glossary', - to: '/docs/references/glossary', - }, - { - from: '/docs/getting-started/create-an-app', - to: '/docs/getting-started/', - }, - { - from: '/docs/getting-started/configuration', - to: '/docs/getting-started/#next-steps', - }, - ], - }, - ], - [ - 'docusaurus-pushfeedback', - { - project: 'q8w1i6cair', - hideIcon: true, - customFont: true, - buttonStyle: 'dark', - }, - ], - ], - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - { - colorMode: { - defaultMode: 'dark', - disableSwitch: true, - }, - navbar: { - logo: { - alt: 'Backstage Software Catalog and Developer Platform', - src: 'img/logo.svg', - }, - items: [ - { - href: 'https://github.com/backstage/backstage', - label: 'GitHub', - position: 'left', - }, - { - to: 'docs/overview/what-is-backstage', - label: 'Docs', - position: 'left', - }, - { - to: '/plugins', - label: 'Plugins', - position: 'left', - }, - { - to: '/blog', - label: 'Blog', - position: 'left', - }, - { - to: 'docs/releases/v1.26.0', - label: 'Releases', - position: 'left', - }, - { - to: '/demos', - label: 'Demos', - position: 'left', - }, - { - to: '/community', - label: 'Community', - position: 'left', - }, - ], - }, - image: 'img/sharing-opengraph.png', - footer: { - links: [ - { - items: [ - { - html: ` - - - `, - }, - ], - }, - { - title: 'Docs', - items: [ - { - label: 'What is Backstage?', - to: 'docs/overview/what-is-backstage', - }, - { - label: 'Getting started', - to: 'docs/getting-started/', - }, - { - label: 'Software Catalog', - to: 'docs/features/software-catalog/', - }, - { - label: 'Create a Plugin', - to: 'docs/plugins/create-a-plugin', - }, - { - label: 'Designing for Backstage', - to: 'docs/dls/design', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Support chatroom', - to: 'https://discord.gg/backstage-687207715902193673', - }, - { - label: 'Contributing', - to: 'https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md', - }, - { - label: 'Adopting', - to: 'https://backstage.spotify.com', - }, - { - label: 'Subscribe to our newsletter', - to: 'https://info.backstage.spotify.com/newsletter_subscribe', - }, - { - label: 'CNCF Incubation', - to: 'https://www.cncf.io/projects/', - }, - ], - }, - { - title: 'More', - items: [ - { - label: 'Open Source @ Spotify', - to: 'https://spotify.github.io/', - }, - { - label: 'Spotify Engineering Blog', - to: 'https://engineering.atspotify.com/', - }, - { - label: 'Spotify for Developers', - to: 'https://developer.spotify.com/', - }, - { - label: 'GitHub', - to: 'https://github.com/backstage/', - }, - ], - }, - ], - copyright: - '

Made with ❤️ at Spotify

', - }, - algolia: { - apiKey: '1f0ba86672ccfc3576faa94583e5b318', - indexName: 'crawler_Backstage Docusaurus 2', - appId: 'JCMFNHCHI8', - searchParameters: {}, - }, - prism: { - theme: prismTheme, - // Supported languages: https://prismjs.com/#supported-languages - // Default languages: https://github.com/FormidableLabs/prism-react-renderer/blob/master/packages/generate-prism-languages/index.ts#L9-L23 - additionalLanguages: ['docker', 'bash'], - magicComments: [ - // Extend the default highlight class name - { - className: 'code-block-highlight-line', - line: 'highlight-next-line', - block: { start: 'highlight-start', end: 'highlight-end' }, - }, - { - className: 'code-block-add-line', - line: 'highlight-add-next-line', - block: { start: 'highlight-add-start', end: 'highlight-add-end' }, - }, - { - className: 'code-block-remove-line', - line: 'highlight-remove-next-line', - block: { - start: 'highlight-remove-start', - end: 'highlight-remove-end', - }, - }, - ], - }, - }, -}; diff --git a/microsite/docusaurus.config.ts b/microsite/docusaurus.config.ts new file mode 100644 index 0000000000..75a67406b6 --- /dev/null +++ b/microsite/docusaurus.config.ts @@ -0,0 +1,362 @@ +/* + * 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. + */ + +// @ts-check + +/** @type{import('prism-react-renderer').PrismTheme} **/ +// @ts-ignore +import { themes } from 'prism-react-renderer'; +import type * as Preset from '@docusaurus/preset-classic'; +import { Config } from '@docusaurus/types'; +const backstageTheme = themes.vsDark; +backstageTheme.plain.backgroundColor = '#232323'; + +const config: Config = { + title: 'Backstage Software Catalog and Developer Platform', + tagline: 'An open source framework for building developer portals', + url: 'https://backstage.io', + baseUrl: '/', + organizationName: 'Spotify', + projectName: 'backstage', + scripts: [ + 'https://buttons.github.io/buttons.js', + 'https://unpkg.com/medium-zoom@1.0.6/dist/medium-zoom.min.js', + '/js/medium-zoom.js', + '/js/dismissable-banner.js', + '/js/scroll-nav-to-view-in-docs.js', + ], + stylesheets: [ + 'https://fonts.googleapis.com/css?family=IBM+Plex+Mono:500,700&display=swap', + ], + favicon: 'img/favicon.ico', + customFields: { + fossWebsite: 'https://spotify.github.io/', + repoUrl: 'https://github.com/backstage/backstage', + }, + onBrokenLinks: 'log', + onBrokenMarkdownLinks: 'log', + presets: [ + [ + '@docusaurus/preset-classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + { + docs: { + editUrl: 'https://github.com/backstage/backstage/edit/master/docs/', + path: '../docs', + sidebarPath: 'sidebars.json', + }, + blog: { + path: 'blog', + }, + theme: { + customCss: 'src/theme/customTheme.scss', + }, + gtag: { + trackingID: 'G-KSEVGGNCJW', + }, + }, + ], + ], + markdown: { + preprocessor({ fileContent }) { + // Replace all HTML comments with empty strings as these are not supported by MDXv2. + function removeHtmlComments(input) { + let previous; + do { + previous = input; + input = input.replace(//gs, ''); + } while (input !== previous); + return input; + } + return removeHtmlComments(fileContent); + }, + format: 'detect', + }, + webpack: { + jsLoader: isServer => ({ + loader: require.resolve('swc-loader'), + options: { + jsc: { + parser: { + syntax: 'typescript', + tsx: true, + }, + target: 'es2017', + }, + module: { + type: isServer ? 'commonjs' : 'es6', + }, + }, + }), + }, + plugins: [ + 'docusaurus-plugin-sass', + () => ({ + name: 'yaml-loader', + configureWebpack() { + return { + module: { + rules: [ + { + test: /\.ya?ml$/, + use: 'yaml-loader', + }, + ], + }, + }; + }, + }), + [ + '@docusaurus/plugin-client-redirects', + { + redirects: [ + { + from: '/docs', + to: '/docs/overview/what-is-backstage', + }, + { + from: '/docs/features/software-catalog/software-catalog-overview', + to: '/docs/features/software-catalog/', + }, + { + from: '/docs/features/software-templates/software-templates-index', + to: '/docs/features/software-templates/', + }, + { + from: '/docs/features/techdocs/techdocs-overview', + to: '/docs/features/techdocs/', + }, + { + from: '/docs/features/kubernetes/overview', + to: '/docs/features/kubernetes/', + }, + { + from: '/docs/features/search/search-overview', + to: '/docs/features/search/', + }, + { + from: '/docs/getting-started/running-backstage-locally', + to: '/docs/getting-started/', + }, + { + from: '/docs/features/software-templates/testing-scaffolder-alpha', + to: '/docs/features/software-templates/migrating-to-rjsf-v5', + }, + { + from: '/docs/auth/glossary', + to: '/docs/references/glossary', + }, + { + from: '/docs/overview/glossary', + to: '/docs/references/glossary', + }, + { + from: '/docs/getting-started/create-an-app', + to: '/docs/getting-started/', + }, + { + from: '/docs/getting-started/configuration', + to: '/docs/getting-started/#next-steps', + }, + { + from: '/docs/features/software-templates/authorizing-parameters-steps-and-actions', + to: '/docs/features/software-templates/authorizing-scaffolder-template-details', + }, + ], + }, + ], + [ + 'docusaurus-pushfeedback', + { + project: 'q8w1i6cair', + hideIcon: true, + customFont: true, + buttonStyle: 'dark', + ratingMode: 'stars', + }, + ], + ], + themeConfig: { + colorMode: { + defaultMode: 'dark', + disableSwitch: true, + }, + navbar: { + logo: { + alt: 'Backstage Software Catalog and Developer Platform', + src: 'img/logo.svg', + }, + items: [ + { + href: 'https://github.com/backstage/backstage', + label: 'GitHub', + position: 'left', + }, + { + to: 'docs/overview/what-is-backstage', + label: 'Docs', + position: 'left', + }, + { + to: '/plugins', + label: 'Plugins', + position: 'left', + }, + { + to: '/blog', + label: 'Blog', + position: 'left', + }, + { + to: 'docs/releases/v1.27.0', + label: 'Releases', + position: 'left', + }, + { + to: '/demos', + label: 'Demos', + position: 'left', + }, + { + to: '/community', + label: 'Community', + position: 'left', + }, + ], + }, + image: 'img/sharing-opengraph.png', + footer: { + links: [ + { + items: [ + { + html: ` + + + `, + }, + ], + }, + { + title: 'Docs', + items: [ + { + label: 'What is Backstage?', + to: 'docs/overview/what-is-backstage', + }, + { + label: 'Getting started', + to: 'docs/getting-started/', + }, + { + label: 'Software Catalog', + to: 'docs/features/software-catalog/', + }, + { + label: 'Create a Plugin', + to: 'docs/plugins/create-a-plugin', + }, + { + label: 'Designing for Backstage', + to: 'docs/dls/design', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Support chatroom', + to: 'https://discord.gg/backstage-687207715902193673', + }, + { + label: 'Contributing', + to: 'https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md', + }, + { + label: 'Adopting', + to: 'https://backstage.spotify.com', + }, + { + label: 'Subscribe to our newsletter', + to: 'https://info.backstage.spotify.com/newsletter_subscribe', + }, + { + label: 'CNCF Incubation', + to: 'https://www.cncf.io/projects/', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Open Source @ Spotify', + to: 'https://spotify.github.io/', + }, + { + label: 'Spotify Engineering Blog', + to: 'https://engineering.atspotify.com/', + }, + { + label: 'Spotify for Developers', + to: 'https://developer.spotify.com/', + }, + { + label: 'GitHub', + to: 'https://github.com/backstage/', + }, + ], + }, + ], + copyright: `

Made with ❤️ at Spotify

`, + }, + algolia: { + apiKey: '1f0ba86672ccfc3576faa94583e5b318', + indexName: 'crawler_Backstage Docusaurus 2', + appId: 'JCMFNHCHI8', + searchParameters: {}, + }, + prism: { + theme: backstageTheme, + // Supported languages: https://prismjs.com/#supported-languages + // Default languages: https://github.com/FormidableLabs/prism-react-renderer/blob/master/packages/generate-prism-languages/index.ts#L9-L23 + additionalLanguages: ['docker', 'bash'], + magicComments: [ + // Extend the default highlight class name + { + className: 'code-block-highlight-line', + line: 'highlight-next-line', + block: { start: 'highlight-start', end: 'highlight-end' }, + }, + { + className: 'code-block-add-line', + line: 'highlight-add-next-line', + block: { start: 'highlight-add-start', end: 'highlight-add-end' }, + }, + { + className: 'code-block-remove-line', + line: 'highlight-remove-next-line', + block: { + start: 'highlight-remove-start', + end: 'highlight-remove-end', + }, + }, + ], + }, + } satisfies Preset.ThemeConfig, +}; +export default config; diff --git a/microsite/package.json b/microsite/package.json index 1be5272286..fc3405c744 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -22,12 +22,14 @@ "@docusaurus/core": "^3.1.1", "@docusaurus/plugin-client-redirects": "^3.1.1", "@docusaurus/preset-classic": "^3.1.1", + "@docusaurus/types": "^3.1.1", + "@mdx-js/react": "^3.0.0", "@swc/core": "^1.3.46", "clsx": "^2.0.0", "docusaurus-plugin-sass": "^0.2.3", "docusaurus-pushfeedback": "^1.0.0", "luxon": "^3.0.0", - "prism-react-renderer": "^1.3.5", + "prism-react-renderer": "^2.1.0", "react": "^18.0.0", "react-dom": "^18.0.0", "sass": "^1.57.1", @@ -35,13 +37,13 @@ }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.1.1", + "@docusaurus/tsconfig": "^3.1.1", "@spotify/prettier-config": "^15.0.0", - "@tsconfig/docusaurus": "^2.0.0", "@types/luxon": "^3.0.0", "@types/webpack-env": "^1.18.0", "js-yaml": "^4.1.0", "prettier": "^2.6.2", - "typescript": "~5.1.0", + "typescript": "~5.2.0", "yaml-loader": "^0.8.0" } } diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 32863c61db..5ddd2f97f1 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.27.0", "releases/v1.26.0", "releases/v1.25.0", "releases/v1.24.0", @@ -68,19 +69,6 @@ "getting-started/keeping-backstage-updated", "getting-started/concepts" ], - "Local Development": [ - { - "type": "category", - "label": "CLI", - "items": [ - "local-dev/cli-overview", - "local-dev/cli-build-system", - "local-dev/cli-commands" - ] - }, - "local-dev/linking-local-packages", - "local-dev/debugging" - ], "Core Features": [ { "type": "category", @@ -129,7 +117,7 @@ "features/software-templates/writing-tests-for-actions", "features/software-templates/writing-custom-field-extensions", "features/software-templates/writing-custom-step-layouts", - "features/software-templates/authorizing-parameters-steps-and-actions", + "features/software-templates/authorizing-scaffolder-template-details", "features/software-templates/migrating-to-rjsf-v5", "features/software-templates/migrating-from-v1beta2-to-v1beta3" ] @@ -238,6 +226,11 @@ "label": "Gitea", "items": ["integrations/gitea/locations"] }, + { + "type": "category", + "label": "Harness", + "items": ["integrations/harness/locations"] + }, { "type": "category", "label": "Google GCS", @@ -352,6 +345,25 @@ ] } ], + "Tooling": [ + { + "type": "category", + "label": "Backstage CLI", + "items": [ + "tooling/cli/overview", + "tooling/cli/build-system", + "tooling/cli/commands" + ] + }, + { + "type": "category", + "label": "Local Development", + "items": [ + "tooling/local-dev/linking-local-packages", + "tooling/local-dev/debugging" + ] + } + ], "Deployment": [ "deployment/index", "deployment/scaling", @@ -493,7 +505,6 @@ "api/deprecations" ], "Tutorials": [ - "tutorials/journey", "tutorials/quickstart-app-plugin", "tutorials/react-router-stable-migration", "tutorials/react18-migration", diff --git a/microsite/static/img/digital.ai-deploy.svg b/microsite/static/img/digital.ai-deploy.svg new file mode 100644 index 0000000000..d0becb98f1 --- /dev/null +++ b/microsite/static/img/digital.ai-deploy.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/microsite/tsconfig.json b/microsite/tsconfig.json index ae8fe2298a..71bc403643 100644 --- a/microsite/tsconfig.json +++ b/microsite/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@tsconfig/docusaurus/tsconfig.json", + "extends": "@docusaurus/tsconfig", "compilerOptions": { "baseUrl": ".", "types": [ diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 259bbca7b0..ebaeb33c2f 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -2160,7 +2160,14 @@ __metadata: languageName: node linkType: hard -"@docusaurus/types@npm:3.2.1": +"@docusaurus/tsconfig@npm:^3.1.1": + version: 3.2.1 + resolution: "@docusaurus/tsconfig@npm:3.2.1" + checksum: ea3c28b79b0de069c50f7b3a67d3ff682b6ded2ef02d2c7a4c2eaeddc8fcf79c9d9f5e60fbd2966cf3d247fbb8f63897b80a61fdd8b485c745a12eb684ae241a + languageName: node + linkType: hard + +"@docusaurus/types@npm:3.2.1, @docusaurus/types@npm:^3.1.1": version: 3.2.1 resolution: "@docusaurus/types@npm:3.2.1" dependencies: @@ -2842,13 +2849,6 @@ __metadata: languageName: node linkType: hard -"@tsconfig/docusaurus@npm:^2.0.0": - version: 2.0.3 - resolution: "@tsconfig/docusaurus@npm:2.0.3" - checksum: d8245a64bf131daa0c287649cb9c37ad8fecb2aedea18e15047e0df6463916e5012af3755bd73ecf90999ace1f14a3748a8b3e041d5158e2a85c22a539c649c9 - languageName: node - linkType: hard - "@types/acorn@npm:^4.0.0": version: 4.0.6 resolution: "@types/acorn@npm:4.0.6" @@ -3237,9 +3237,9 @@ __metadata: linkType: hard "@types/webpack-env@npm:^1.18.0": - version: 1.18.4 - resolution: "@types/webpack-env@npm:1.18.4" - checksum: f195b3ae974ac3b631477b57737dad7b6c44ecca86770cf3c29f284e02961c9f2dfc619e3e253d8c23966864cb052b1e8437e9834ede32ac97972e6e2235bb51 + version: 1.18.5 + resolution: "@types/webpack-env@npm:1.18.5" + checksum: 4ca8eb4c44e1e1807c3e245442fce7aaf2816a163056de9436bbac44cc47c8bc5b1c9a330dc05748d6616431b1fb5bd5379733fb1da0b78d03c59f4ec824c184 languageName: node linkType: hard @@ -3847,9 +3847,11 @@ __metadata: "@docusaurus/module-type-aliases": ^3.1.1 "@docusaurus/plugin-client-redirects": ^3.1.1 "@docusaurus/preset-classic": ^3.1.1 + "@docusaurus/tsconfig": ^3.1.1 + "@docusaurus/types": ^3.1.1 + "@mdx-js/react": ^3.0.0 "@spotify/prettier-config": ^15.0.0 "@swc/core": ^1.3.46 - "@tsconfig/docusaurus": ^2.0.0 "@types/luxon": ^3.0.0 "@types/webpack-env": ^1.18.0 clsx: ^2.0.0 @@ -3858,12 +3860,12 @@ __metadata: js-yaml: ^4.1.0 luxon: ^3.0.0 prettier: ^2.6.2 - prism-react-renderer: ^1.3.5 + prism-react-renderer: ^2.1.0 react: ^18.0.0 react-dom: ^18.0.0 sass: ^1.57.1 swc-loader: ^0.2.3 - typescript: ~5.1.0 + typescript: ~5.2.0 yaml-loader: ^0.8.0 languageName: unknown linkType: soft @@ -4332,9 +4334,9 @@ __metadata: linkType: hard "clsx@npm:^2.0.0": - version: 2.1.0 - resolution: "clsx@npm:2.1.0" - checksum: 43fefc29b6b49c9476fbce4f8b1cc75c27b67747738e598e6651dd40d63692135dc60b18fa1c5b78a2a9ba8ae6fd2055a068924b94e20b42039bd53b78b98e1d + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: acd3e1ab9d8a433ecb3cc2f6a05ab95fe50b4a3cfc5ba47abb6cbf3754585fcb87b84e90c822a1f256c4198e3b41c7f6c391577ffc8678ad587fc0976b24fd57 languageName: node linkType: hard @@ -9583,16 +9585,7 @@ __metadata: languageName: node linkType: hard -"prism-react-renderer@npm:^1.3.5": - version: 1.3.5 - resolution: "prism-react-renderer@npm:1.3.5" - peerDependencies: - react: ">=0.14.9" - checksum: c18806dcbc4c0b4fd6fd15bd06b4f7c0a6da98d93af235c3e970854994eb9b59e23315abb6cfc29e69da26d36709a47e25da85ab27fed81b6812f0a52caf6dfa - languageName: node - linkType: hard - -"prism-react-renderer@npm:^2.3.0": +"prism-react-renderer@npm:^2.1.0, prism-react-renderer@npm:^2.3.0": version: 2.3.1 resolution: "prism-react-renderer@npm:2.3.1" dependencies: @@ -11273,23 +11266,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:~5.1.0": - version: 5.1.6 - resolution: "typescript@npm:5.1.6" +"typescript@npm:~5.2.0": + version: 5.2.2 + resolution: "typescript@npm:5.2.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: b2f2c35096035fe1f5facd1e38922ccb8558996331405eb00a5111cc948b2e733163cc22fab5db46992aba7dd520fff637f2c1df4996ff0e134e77d3249a7350 + checksum: 7912821dac4d962d315c36800fe387cdc0a6298dba7ec171b350b4a6e988b51d7b8f051317786db1094bd7431d526b648aba7da8236607febb26cf5b871d2d3c languageName: node linkType: hard -"typescript@patch:typescript@~5.1.0#~builtin": - version: 5.1.6 - resolution: "typescript@patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=5da071" +"typescript@patch:typescript@~5.2.0#~builtin": + version: 5.2.2 + resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=f3b441" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: f53bfe97f7c8b2b6d23cf572750d4e7d1e0c5fff1c36d859d0ec84556a827b8785077bc27676bf7e71fae538e517c3ecc0f37e7f593be913d884805d931bc8be + checksum: 0f4da2f15e6f1245e49db15801dbee52f2bbfb267e1c39225afdab5afee1a72839cd86000e65ee9d7e4dfaff12239d28beaf5ee431357fcced15fb08583d72ca languageName: node linkType: hard diff --git a/mkdocs.yml b/mkdocs.yml index 7ba6fdfefa..026e76d531 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -33,12 +33,6 @@ nav: - Create a component: 'getting-started/create-a-component.md' - Keeping Backstage Updated: 'getting-started/keeping-backstage-updated.md' - Key Concepts: 'getting-started/concepts.md' - - Local Development: - - CLI: - - Overview: 'local-dev/cli-overview.md' - - Build System: 'local-dev/cli-build-system.md' - - Commands: 'local-dev/cli-commands.md' - - Linking in Local Packages: 'local-dev/linking-local-packages.md' - Core Features: - Software Catalog: - Overview: 'features/software-catalog/index.md' @@ -178,6 +172,14 @@ nav: - Contributing New Providers: 'auth/add-auth-provider.md' - Service to Service Auth: 'auth/service-to-service-auth.md' - Troubleshooting Auth: 'auth/troubleshooting.md' + - Tooling: + - Backstage CLI: + - Overview: 'tooling/cli/01-overview.md' + - Build System: 'tooling/cli/02-build-system.md' + - Commands: 'tooling/cli/03-commands.md' + - Local Development: + - Linking in Local Packages: 'tooling/local-dev/linking-local-packages.md' + - Debugging Backstage: 'tooling/local-dev/debugging.md' - Deployment: - Deploying Backstage: 'deployment/index.md' - Scaling: 'deployment/scaling.md' @@ -195,7 +197,6 @@ nav: - Utility APIs: 'api/utility-apis.md' - Deprecations: 'api/deprecations.md' - Tutorials: - - Future developer journey: 'tutorials/journey.md' - React Router 6.0 Migration: 'tutorials/react-router-stable-migration.md' - Package Role Migration: 'tutorials/package-role-migration.md' - Migrating away from @backstage/core: 'tutorials/migrating-away-from-core.md' diff --git a/package.json b/package.json index abae1b54ec..4486c64afd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.27.0-next.0", + "version": "1.28.0-next.1", "private": true, "repository": { "type": "git", @@ -24,7 +24,7 @@ "clean": "backstage-cli repo clean", "create-plugin": "echo \"use 'yarn new' instead\"", "dev": "yarn workspaces foreach -A --include example-backend --include example-app --parallel -v -i run start", - "dev:next": "yarn workspaces foreach -A --include example-backend-next --include example-app-next --parallel -v -i run start", + "dev:next": "yarn workspaces foreach -A --include example-backend --include example-app-next --parallel -v -i run start", "docker-build": "yarn tsc && yarn workspace example-backend build && yarn workspace example-backend build-image", "fix": "backstage-cli repo fix", "postinstall": "husky || true", @@ -41,8 +41,8 @@ "snyk:test:package": "yarn snyk:test --include", "start": "yarn workspace example-app start", "start-backend": "yarn workspace example-backend start", - "start-backend:next": "yarn workspace example-backend-next start", - "start:lighthouse": "yarn workspaces foreach -A --include example-backend-next --include example-app --parallel -v -i run start", + "start-backend:legacy": "yarn workspace example-backend-legacy start", + "start:lighthouse": "yarn workspaces foreach -A --include example-backend --include example-app --parallel -v -i run start", "start:microsite": "cd microsite/ && yarn start", "start:next": "yarn workspace example-app-next start", "storybook": "yarn --cwd storybook && yarn --cwd storybook start", @@ -84,6 +84,7 @@ }, "prettier": "@spotify/prettier-config", "resolutions": { + "@changesets/assemble-release-plan@^6.0.0": "patch:@changesets/assemble-release-plan@npm%3A6.0.0#./.yarn/patches/@changesets-assemble-release-plan-npm-6.0.0-f7b3005037.patch", "@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch", "@material-ui/pickers@^3.3.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch", "@types/react": "^18", @@ -128,7 +129,7 @@ "shx": "^0.3.2", "sloc": "^0.3.1", "sort-package-json": "^2.8.0", - "typescript": "~5.1.0" + "typescript": "~5.2.0" }, "packageManager": "yarn@3.8.1", "engines": { diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 9efa40b6cc..be98cfedeb 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/app-defaults +## 1.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/plugin-permission-react@0.4.22 + +## 1.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + +## 1.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + ## 1.5.5-next.0 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index ad9986a29a..473f7e76ac 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.5.5-next.0", + "version": "1.5.6-next.0", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index 33f564936a..a54715b18d 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,29 @@ # app-next-example-plugin +## 0.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/frontend-plugin-api@0.6.6-next.0 + +## 0.0.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/frontend-plugin-api@0.6.5 + +## 0.0.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + ## 0.0.11-next.0 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index acd85fc7cb..cba0c558a5 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.11-next.0", + "version": "0.0.12-next.0", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin" diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 1188aff451..4a58195198 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,167 @@ # example-app-next +## 0.0.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.7-next.1 + - @backstage/plugin-catalog-import@0.12.0-next.1 + - @backstage/plugin-kubernetes@0.11.11-next.1 + - @backstage/plugin-search@1.4.12-next.1 + - @backstage/plugin-notifications@0.2.2-next.1 + - @backstage/plugin-scaffolder-react@1.8.7-next.1 + - @backstage/plugin-scaffolder@1.20.2-next.1 + - @backstage/plugin-catalog@1.20.1-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.1 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## 0.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.6-next.0 + - @backstage/plugin-notifications@0.2.2-next.0 + - @backstage/plugin-scaffolder-react@1.8.6-next.0 + - @backstage/theme@0.5.6-next.0 + - @backstage/plugin-api-docs@0.11.6-next.0 + - @backstage/cli@0.26.6-next.0 + - @backstage/plugin-scaffolder@1.20.1-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/frontend-app-api@0.7.1-next.0 + - @backstage/plugin-home@0.7.5-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/plugin-signals@0.0.7-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/plugin-user-settings@0.8.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-app-visualizer@0.1.7-next.0 + - @backstage/plugin-auth-react@0.1.3-next.0 + - @backstage/plugin-catalog@1.20.1-next.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-graph@0.4.6-next.0 + - @backstage/plugin-catalog-import@0.11.1-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.5-next.0 + - @backstage/plugin-kubernetes@0.11.11-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.0 + - @backstage/plugin-org@0.6.26-next.0 + - @backstage/plugin-permission-react@0.4.22 + - @backstage/plugin-search@1.4.12-next.0 + - @backstage/plugin-search-common@1.2.11 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.11-next.0 + +## 0.0.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5 + - @backstage/plugin-scaffolder@1.20.0 + - @backstage/plugin-user-settings@0.8.6 + - @backstage/plugin-catalog@1.20.0 + - @backstage/plugin-notifications@0.2.1 + - @backstage/core-compat-api@0.2.5 + - @backstage/plugin-api-docs@0.11.5 + - @backstage/plugin-home@0.7.4 + - @backstage/cli@0.26.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-techdocs@1.10.5 + - @backstage/plugin-catalog-import@0.11.0 + - @backstage/frontend-app-api@0.7.0 + - @backstage/plugin-auth-react@0.1.2 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/plugin-catalog-graph@0.4.5 + - @backstage/plugin-search@1.4.11 + - @backstage/plugin-org@0.6.25 + - @backstage/app-defaults@1.5.5 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-app-visualizer@0.1.6 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4 + - @backstage/plugin-kubernetes@0.11.10 + - @backstage/plugin-kubernetes-cluster@0.0.11 + - @backstage/plugin-search-react@1.7.11 + - @backstage/plugin-signals@0.0.6 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10 + - @backstage/plugin-techdocs-react@1.2.4 + +## 0.0.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.5-next.1 + - @backstage/frontend-app-api@0.7.0-next.2 + - @backstage/plugin-techdocs@1.10.5-next.2 + - @backstage/plugin-notifications@0.2.1-next.2 + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/plugin-api-docs@0.11.5-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/plugin-scaffolder@1.19.4-next.2 + - @backstage/plugin-search@1.4.11-next.2 + - @backstage/plugin-org@0.6.25-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.2 + - @backstage/plugin-catalog-import@0.10.11-next.2 + - @backstage/plugin-home@0.7.4-next.2 + - @backstage/plugin-kubernetes@0.11.10-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.2 + - @backstage/plugin-scaffolder-react@1.8.5-next.2 + - @backstage/plugin-user-settings@0.8.6-next.2 + - @backstage/integration-react@1.1.27-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.2 + +## 0.0.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5-next.1 + - @backstage/plugin-scaffolder@1.19.4-next.1 + - @backstage/plugin-notifications@0.2.1-next.1 + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/cli@0.26.5-next.0 + - @backstage/frontend-app-api@0.6.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-api-docs@0.11.5-next.1 + - @backstage/plugin-app-visualizer@0.1.6-next.1 + - @backstage/plugin-auth-react@0.1.2-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.1 + - @backstage/plugin-catalog-import@0.10.11-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4-next.1 + - @backstage/plugin-home@0.7.4-next.1 + - @backstage/plugin-kubernetes@0.11.10-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.1 + - @backstage/plugin-org@0.6.25-next.1 + - @backstage/plugin-search@1.4.11-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-signals@0.0.6-next.1 + - @backstage/plugin-techdocs@1.10.5-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + - @backstage/plugin-user-settings@0.8.6-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + ## 0.0.11-next.0 ### Patch Changes diff --git a/packages/app-next/README.md b/packages/app-next/README.md index 360e5d5545..203aaa9f79 100644 --- a/packages/app-next/README.md +++ b/packages/app-next/README.md @@ -4,4 +4,4 @@ This package is an example of a Backstage application using the [new frontend](. To play with it, open a terminal and run the command: `yarn start` -**NOTE:** Don't forget to open a second terminal and to launch the backend or [backend-next](../../docs/backend-system/index.md) there, using `yarn start`! The frontend requires a backend to connect to. +**NOTE:** Don't forget to open a second terminal and to launch the backend there, using `yarn start`! The frontend requires a backend to connect to. diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 065aa43322..3b1bf6a29a 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.11-next.0", + "version": "0.0.12-next.1", "private": true, "repository": { "type": "git", diff --git a/packages/app-next/public/index.html b/packages/app-next/public/index.html index 1bbfda590d..63ab0bec0c 100644 --- a/packages/app-next/public/index.html +++ b/packages/app-next/public/index.html @@ -72,7 +72,10 @@ site: '<%= config.getOptionalString("app.datadogRum.site") || "datadoghq.com" %>', service: 'backstage', env: '<%= config.getString("app.datadogRum.env") %>', - sampleRate: 100, + sampleRate: + '<%= config.getOptionalNumber("app.datadogRum.sessionSampleRate") || 100 %>', + sessionReplaySampleRate: + '<%= config.getOptionalNumber("app.datadogRum.sessionReplaySampleRate") || 0 %>', trackInteractions: true, }); }); diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 83b921aea1..c911a01258 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -80,7 +80,7 @@ TODO: const homePageExtension = createExtension({ name: 'myhomepage', - attachTo: { id: 'home', input: 'props' }, + attachTo: { id: 'page:home', input: 'props' }, output: { children: coreExtensionData.reactElement, title: titleExtensionDataRef, diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 10c2873bc4..01e12da7db 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,159 @@ # example-app +## 0.2.98-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.7-next.1 + - @backstage/plugin-catalog-import@0.12.0-next.1 + - @backstage/plugin-kubernetes@0.11.11-next.1 + - @backstage/plugin-search@1.4.12-next.1 + - @backstage/plugin-notifications@0.2.2-next.1 + - @backstage/plugin-scaffolder-react@1.8.7-next.1 + - @backstage/plugin-scaffolder@1.20.2-next.1 + - @backstage/plugin-catalog@1.20.1-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.1 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## 0.2.98-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.6-next.0 + - @backstage/plugin-notifications@0.2.2-next.0 + - @backstage/plugin-scaffolder-react@1.8.6-next.0 + - @backstage/theme@0.5.6-next.0 + - @backstage/plugin-api-docs@0.11.6-next.0 + - @backstage/cli@0.26.6-next.0 + - @backstage/plugin-scaffolder@1.20.1-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/frontend-app-api@0.7.1-next.0 + - @backstage/plugin-home@0.7.5-next.0 + - @backstage/plugin-search-react@1.7.12-next.0 + - @backstage/plugin-signals@0.0.7-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/plugin-user-settings@0.8.7-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-auth-react@0.1.3-next.0 + - @backstage/plugin-catalog@1.20.1-next.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-graph@0.4.6-next.0 + - @backstage/plugin-catalog-import@0.11.1-next.0 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.5-next.0 + - @backstage/plugin-devtools@0.1.15-next.0 + - @backstage/plugin-kubernetes@0.11.11-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.12-next.0 + - @backstage/plugin-org@0.6.26-next.0 + - @backstage/plugin-permission-react@0.4.22 + - @backstage/plugin-search@1.4.12-next.0 + - @backstage/plugin-search-common@1.2.11 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.11-next.0 + +## 0.2.97 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5 + - @backstage/plugin-scaffolder@1.20.0 + - @backstage/plugin-user-settings@0.8.6 + - @backstage/plugin-catalog@1.20.0 + - @backstage/plugin-notifications@0.2.1 + - @backstage/plugin-api-docs@0.11.5 + - @backstage/plugin-home@0.7.4 + - @backstage/cli@0.26.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-techdocs@1.10.5 + - @backstage/plugin-catalog-import@0.11.0 + - @backstage/frontend-app-api@0.7.0 + - @backstage/plugin-auth-react@0.1.2 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/plugin-catalog-graph@0.4.5 + - @backstage/plugin-search@1.4.11 + - @backstage/plugin-org@0.6.25 + - @backstage/app-defaults@1.5.5 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4 + - @backstage/plugin-devtools@0.1.14 + - @backstage/plugin-kubernetes@0.11.10 + - @backstage/plugin-kubernetes-cluster@0.0.11 + - @backstage/plugin-search-react@1.7.11 + - @backstage/plugin-signals@0.0.6 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10 + - @backstage/plugin-techdocs-react@1.2.4 + +## 0.2.97-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.5-next.1 + - @backstage/frontend-app-api@0.7.0-next.2 + - @backstage/plugin-techdocs@1.10.5-next.2 + - @backstage/plugin-notifications@0.2.1-next.2 + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/plugin-api-docs@0.11.5-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/plugin-scaffolder@1.19.4-next.2 + - @backstage/plugin-search@1.4.11-next.2 + - @backstage/plugin-org@0.6.25-next.2 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.2 + - @backstage/plugin-catalog-import@0.10.11-next.2 + - @backstage/plugin-home@0.7.4-next.2 + - @backstage/plugin-kubernetes@0.11.10-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.2 + - @backstage/plugin-scaffolder-react@1.8.5-next.2 + - @backstage/plugin-user-settings@0.8.6-next.2 + - @backstage/integration-react@1.1.27-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.2 + +## 0.2.97-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.8.5-next.1 + - @backstage/plugin-scaffolder@1.19.4-next.1 + - @backstage/plugin-notifications@0.2.1-next.1 + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/cli@0.26.5-next.0 + - @backstage/frontend-app-api@0.6.5-next.1 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-api-docs@0.11.5-next.1 + - @backstage/plugin-auth-react@0.1.2-next.1 + - @backstage/plugin-catalog-graph@0.4.5-next.1 + - @backstage/plugin-catalog-import@0.10.11-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.4-next.1 + - @backstage/plugin-devtools@0.1.14-next.1 + - @backstage/plugin-home@0.7.4-next.1 + - @backstage/plugin-kubernetes@0.11.10-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.11-next.1 + - @backstage/plugin-org@0.6.25-next.1 + - @backstage/plugin-search@1.4.11-next.1 + - @backstage/plugin-search-react@1.7.11-next.1 + - @backstage/plugin-signals@0.0.6-next.1 + - @backstage/plugin-techdocs@1.10.5-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.10-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + - @backstage/plugin-user-settings@0.8.6-next.1 + ## 0.2.97-next.0 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index b0e3a8fee3..c62624c770 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.97-next.0", + "version": "0.2.98-next.1", "backstage": { "role": "frontend" }, diff --git a/packages/app/public/index.html b/packages/app/public/index.html index 631666da28..9a8267e98e 100644 --- a/packages/app/public/index.html +++ b/packages/app/public/index.html @@ -72,7 +72,10 @@ site: '<%= config.getOptionalString("app.datadogRum.site") || "datadoghq.com" %>', service: 'backstage', env: '<%= config.getString("app.datadogRum.env") %>', - sampleRate: 100, + sampleRate: + '<%= config.getOptionalNumber("app.datadogRum.sessionSampleRate") || 100 %>', + sessionReplaySampleRate: + '<%= config.getOptionalNumber("app.datadogRum.sessionReplaySampleRate") || 0 %>', trackInteractions: true, }); }); diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 30515c50ff..74d39824e0 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,86 @@ # @backstage/backend-app-api +## 0.7.6-next.1 + +### Patch Changes + +- 398b82a: Add support for JWKS tokens in ExternalTokenHandler. +- 9e63318: Added an optional `accessRestrictions` to external access service tokens and service principals in general, such that you can limit their access to certain plugins or permissions. +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## 0.7.6-next.0 + +### Patch Changes + +- b7de623: Fixed a potential crash when passing an object with a `null` prototype as log meta. +- 7d30d95: Fixing issue with log meta fields possibly being circular refs +- 6a576dc: Stop using `getVoidLogger` in tests to reduce the dependency on the soon-to-deprecate `backstage-common` package. +- 6551b3d: Deprecated core service factories and implementations and moved them over to + subpath exports on `@backstage/backend-defaults` instead. E.g. + `@backstage/backend-defaults/scheduler` is where the service factory and default + implementation of `coreServices.scheduler` now lives. +- d617103: Updating the logger redaction message to something less dramatic +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.7.3 + +### Patch Changes + +- 4cd5ff0: Add ability to configure the Node.js HTTP Server when configuring the root HTTP Router service +- e8199b1: Move the JWKS registration outside of the lifecycle middleware +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- dc8c5dd: The default `TokenManager` implementation no longer requires keys to be configured in production, but it will throw an errors when generating or authenticating tokens. The default `AuthService` implementation will now also provide additional context if such an error is throw when falling back to using the `TokenManager` service to generate tokens for outgoing requests. +- 025641b: Redact `meta` fields too with the logger +- 09f8988: Remove explicit `alg` check for user tokens in `verifyToken` +- 5863e02: Internal refactor to only create one external token handler +- a1dc547: Added support for camel case CSP directives in app-config. For example: + + ```yaml + backend: + csp: + upgradeInsecureRequests: false + ``` + +- 329cc34: Added logging of all plugins being initialized, periodic status, and completion. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-permission-node@0.7.29 + +## 0.7.2-next.1 + +### Patch Changes + +- 09f8988: Remove explicit `alg` check for user tokens in `verifyToken` +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/cli-node@0.2.5 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + ## 0.7.1-next.0 ### Patch Changes diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 5720c1c60f..11d9dd90d4 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -8,7 +8,7 @@ import type { AppConfig } from '@backstage/config'; import { AuthService } from '@backstage/backend-plugin-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; -import { CacheClient } from '@backstage/backend-common'; +import { CacheService } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; import { ConfigSchema } from '@backstage/config-loader'; import { CorsOptions } from 'cors'; @@ -65,8 +65,8 @@ export interface Backend { stop(): Promise; } -// @public (undocumented) -export const cacheServiceFactory: () => ServiceFactory; +// @public @deprecated (undocumented) +export const cacheServiceFactory: () => ServiceFactory; // @public (undocumented) export function createConfigSecretEnumerator(options: { @@ -100,7 +100,7 @@ export interface CreateSpecializedBackendOptions { defaultServiceFactories: ServiceFactoryOrFunction[]; } -// @public (undocumented) +// @public @deprecated (undocumented) export const databaseServiceFactory: () => ServiceFactory< PluginDatabaseManager, 'plugin' @@ -121,7 +121,7 @@ export interface DefaultRootHttpRouterOptions { indexPath?: string | false; } -// @public (undocumented) +// @public @deprecated (undocumented) export const discoveryServiceFactory: () => ServiceFactory< DiscoveryService, 'plugin' @@ -137,7 +137,7 @@ export interface ExtendedHttpServer extends http.Server { stop(): Promise; } -// @public +// @public @deprecated export class HostDiscovery implements DiscoveryService { static fromConfig( config: Config, @@ -190,13 +190,13 @@ export type HttpServerOptions = { }; }; -// @public +// @public @deprecated export type IdentityFactoryOptions = { issuer?: string; algorithms?: string[]; }; -// @public (undocumented) +// @public @deprecated (undocumented) export const identityServiceFactory: ( options?: IdentityFactoryOptions | undefined, ) => ServiceFactory; @@ -208,7 +208,7 @@ export interface LifecycleMiddlewareOptions { startupRequestPauseTimeout?: HumanDuration; } -// @public +// @public @deprecated export const lifecycleServiceFactory: () => ServiceFactory< LifecycleService, 'plugin' @@ -255,7 +255,7 @@ export interface MiddlewareFactoryOptions { logger: LoggerService; } -// @public (undocumented) +// @public @deprecated (undocumented) export const permissionsServiceFactory: () => ServiceFactory< PermissionsService, 'plugin' @@ -270,7 +270,7 @@ export function readHelmetOptions(config?: Config): HelmetOptions; // @public export function readHttpServerOptions(config?: Config): HttpServerOptions; -// @public (undocumented) +// @public @deprecated (undocumented) export interface RootConfigFactoryOptions { argv?: string[]; remote?: Pick; @@ -278,7 +278,7 @@ export interface RootConfigFactoryOptions { watch?: boolean; } -// @public (undocumented) +// @public @deprecated (undocumented) export const rootConfigServiceFactory: ( options?: RootConfigFactoryOptions | undefined, ) => ServiceFactory; @@ -314,7 +314,7 @@ export const rootHttpRouterServiceFactory: ( options?: RootHttpRouterFactoryOptions | undefined, ) => ServiceFactory; -// @public +// @public @deprecated export const rootLifecycleServiceFactory: () => ServiceFactory< RootLifecycleService, 'root' @@ -326,19 +326,19 @@ export const rootLoggerServiceFactory: () => ServiceFactory< 'root' >; -// @public (undocumented) +// @public @deprecated (undocumented) export const schedulerServiceFactory: () => ServiceFactory< SchedulerService, 'plugin' >; -// @public (undocumented) +// @public @deprecated (undocumented) export const tokenManagerServiceFactory: () => ServiceFactory< TokenManagerService, 'plugin' >; -// @public (undocumented) +// @public @deprecated (undocumented) export const urlReaderServiceFactory: () => ServiceFactory; // @public (undocumented) diff --git a/packages/backend-app-api/config.d.ts b/packages/backend-app-api/config.d.ts index f84493828a..80f97cb4b5 100644 --- a/packages/backend-app-api/config.d.ts +++ b/packages/backend-app-api/config.d.ts @@ -88,6 +88,46 @@ export interface Config { */ subject: 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; + }; + }>; } | { /** @@ -130,6 +170,87 @@ export interface Config { */ subject: 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; + }; + }>; + } + | { + /** + * This access method consists of a JWKS endpoint that can be used to + * verify JWT tokens. + * + * Callers generate JWT tokens via 3rd party tooling + * and pass them in the Authorization header: + * + * ``` + * Authorization: Bearer eZv5o+fW3KnR3kVabMW4ZcDNLPl8nmMW + * ``` + */ + type: 'jwks'; + options: { + /** + * The full URL of the JWKS endpoint. + */ + url: string; + /** + * Sets the algorithm(s) that should be used to verify the JWT tokens. + * The passed JWTs must have been signed using one of the listed algorithms. + */ + algorithm?: string | string[]; + /** + * Sets the issuer(s) that should be used to verify the JWT tokens. + * Passed JWTs must have an `iss` claim which matches one of the specified issuers. + */ + issuer?: string | string[]; + /** + * Sets the audience(s) that should be used to verify the JWT tokens. + * The passed JWTs must have an "aud" claim that matches one of the audiences specified, + * or have no audience specified. + */ + audience?: string | string[]; + /** + * Sets an optional subject prefix. Passes the subject to called plugins. + * Useful for debugging and tracking purposes. + */ + subjectPrefix?: string; + }; } >; }; diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 09ff295f8d..d2f21e4998 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.1-next.0", + "version": "0.7.6-next.1", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" @@ -83,6 +83,7 @@ "path-to-regexp": "^6.2.1", "selfsigned": "^2.0.0", "stoppable": "^1.1.0", + "triple-beam": "^1.4.1", "uuid": "^9.0.0", "winston": "^3.2.1", "winston-transport": "^4.5.0" diff --git a/packages/backend-app-api/src/http/readHelmetOptions.test.ts b/packages/backend-app-api/src/http/readHelmetOptions.test.ts index bc31404634..97daef359a 100644 --- a/packages/backend-app-api/src/http/readHelmetOptions.test.ts +++ b/packages/backend-app-api/src/http/readHelmetOptions.test.ts @@ -47,7 +47,8 @@ describe('readHelmetOptions', () => { csp: { key: ['value'], 'img-src': false, - 'script-src-attr': ['custom'], + scriptSrcAttr: ['custom'], + 'object-src': ['asd'], }, }); expect(readHelmetOptions(config)).toEqual({ @@ -58,7 +59,7 @@ describe('readHelmetOptions', () => { 'base-uri': ["'self'"], 'font-src': ["'self'", 'https:', 'data:'], 'frame-ancestors': ["'self'"], - 'object-src': ["'none'"], + 'object-src': ['asd'], 'script-src': ["'self'", "'unsafe-eval'"], 'style-src': ["'self'", 'https:', "'unsafe-inline'"], 'script-src-attr': ['custom'], diff --git a/packages/backend-app-api/src/http/readHelmetOptions.ts b/packages/backend-app-api/src/http/readHelmetOptions.ts index 0555bdef00..510fdd9586 100644 --- a/packages/backend-app-api/src/http/readHelmetOptions.ts +++ b/packages/backend-app-api/src/http/readHelmetOptions.ts @@ -18,6 +18,7 @@ import { Config } from '@backstage/config'; import helmet from 'helmet'; import { HelmetOptions } from 'helmet'; import { ContentSecurityPolicyOptions } from 'helmet/dist/types/middlewares/content-security-policy'; +import kebabCase from 'lodash/kebabCase'; /** * Attempts to read Helmet options from the backend configuration object. @@ -97,10 +98,11 @@ export function applyCspDirectives( if (directives) { for (const [key, value] of Object.entries(directives)) { + const kebabCaseKey = kebabCase(key); if (value === false) { - delete result[key]; + delete result[kebabCaseKey]; } else { - result[key] = value; + result[kebabCaseKey] = value; } } } diff --git a/packages/backend-app-api/src/logging/WinstonLogger.test.ts b/packages/backend-app-api/src/logging/WinstonLogger.test.ts index c7173b1cbe..0f9e079943 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.test.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.test.ts @@ -14,37 +14,83 @@ * limitations under the License. */ -import { TransformableInfo } from 'logform'; +import { format } from 'logform'; import { WinstonLogger } from './WinstonLogger'; - -function msg(info: TransformableInfo): TransformableInfo { - return { message: info.message, level: info.level, stack: info.stack }; -} +import Transport from 'winston-transport'; +import { MESSAGE } from 'triple-beam'; describe('WinstonLogger', () => { - it('redacter should redact and escape regex', () => { - const redacter = WinstonLogger.redacter(); - const log = { - level: 'error', - message: 'hello (world)', - stack: 'hello (world) from this file', - }; - expect(redacter.format.transform(msg(log))).toEqual(msg(log)); - redacter.add(['hello\n']); - expect(redacter.format.transform(msg(log))).toEqual( - msg({ - ...log, - message: '[REDACTED] (world)', - stack: '[REDACTED] (world) from this file', + it('creates a winston logger instance with default options', () => { + const logger = WinstonLogger.create({}); + expect(logger).toBeInstanceOf(WinstonLogger); + }); + + it('creates a child logger', () => { + const logger = WinstonLogger.create({}); + const childLogger = logger.child({ plugin: 'test-plugin' }); + expect(childLogger).toBeInstanceOf(WinstonLogger); + }); + + it('should redact and escape regex', () => { + const mockTransport = new Transport({ + log: jest.fn(), + logv: jest.fn(), + }); + + const logger = WinstonLogger.create({ + format: format.json(), + transports: [mockTransport], + }); + + logger.addRedactions(['hello (world']); + + logger.error('hello (world) from this file'); + + expect(mockTransport.log).toHaveBeenCalledWith( + expect.objectContaining({ + [MESSAGE]: JSON.stringify({ + level: 'error', + message: '***) from this file', + }), }), + expect.any(Function), ); - redacter.add(['(world']); - expect(redacter.format.transform(msg(log))).toEqual( - msg({ - ...log, - message: '[REDACTED] [REDACTED])', - stack: '[REDACTED] [REDACTED]) from this file', + }); + + it('should redact nested object', () => { + const mockTransport = new Transport({ + log: jest.fn(), + logv: jest.fn(), + }); + + const logger = WinstonLogger.create({ + format: format.json(), + transports: [mockTransport], + }); + + logger.addRedactions(['hello']); + + logger.error('something went wrong', { + null: null, + nested: 'hello (world) from nested object', + nullProto: Object.create(null, { + foo: { value: 'hello foo', enumerable: true }, }), + }); + + expect(mockTransport.log).toHaveBeenCalledWith( + expect.objectContaining({ + [MESSAGE]: JSON.stringify({ + level: 'error', + message: 'something went wrong', + nested: '*** (world) from nested object', + null: null, + nullProto: { + foo: '*** foo', + }, + }), + }), + expect.any(Function), ); }); }); diff --git a/packages/backend-app-api/src/logging/WinstonLogger.ts b/packages/backend-app-api/src/logging/WinstonLogger.ts index 8d4b37bb8d..64e97b230c 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.ts @@ -27,6 +27,7 @@ import { transports, transport as Transport, } from 'winston'; +import { MESSAGE } from 'triple-beam'; import { escapeRegExp } from '../lib/escapeRegExp'; /** @@ -61,8 +62,8 @@ export class WinstonLogger implements RootLoggerService { let logger = createLogger({ level: process.env.LOG_LEVEL || options.level || 'info', format: format.combine( - redacter.format, options.format ?? defaultFormatter, + redacter.format, ), transports: options.transports ?? new transports.Console(), }); @@ -85,20 +86,16 @@ export class WinstonLogger implements RootLoggerService { let redactionPattern: RegExp | undefined = undefined; - const replace = (obj: TransformableInfo) => { - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - if (typeof obj[key] === 'object') { - obj[key] = replace(obj[key] as TransformableInfo); - } else if (typeof obj[key] === 'string') { - obj[key] = obj[key]?.replace(redactionPattern, '[REDACTED]'); - } - } - } - return obj; - }; return { - format: format(replace)(), + format: format((obj: TransformableInfo) => { + if (!redactionPattern || !obj) { + return obj; + } + + obj[MESSAGE] = obj[MESSAGE]?.replace?.(redactionPattern, '***'); + + return obj; + })(), add(newRedactions) { let added = 0; for (const redactionToTrim of newRedactions) { diff --git a/packages/backend-app-api/src/services/implementations/auth/DatabaseKeyStore.ts b/packages/backend-app-api/src/services/implementations/auth/DatabaseKeyStore.ts index 6a1536fd18..5bf9244707 100644 --- a/packages/backend-app-api/src/services/implementations/auth/DatabaseKeyStore.ts +++ b/packages/backend-app-api/src/services/implementations/auth/DatabaseKeyStore.ts @@ -14,11 +14,14 @@ * limitations under the License. */ -import { DatabaseService, LoggerService } from '@backstage/backend-plugin-api'; +import { + DatabaseService, + LoggerService, + resolvePackagePath, +} from '@backstage/backend-plugin-api'; import { DateTime } from 'luxon'; import { Knex } from 'knex'; import { JsonObject } from '@backstage/types'; -import { resolvePackagePath } from '@backstage/backend-common'; import { KeyStore } from './types'; const MIGRATIONS_TABLE = 'backstage_backend_public_keys__knex_migrations'; diff --git a/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts b/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts index dc76a8761b..b4feb46cce 100644 --- a/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts +++ b/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts @@ -82,7 +82,11 @@ export class DefaultAuthService implements AuthService { const externalResult = await this.externalTokenHandler.verifyToken(token); if (externalResult) { - return createCredentialsWithServicePrincipal(externalResult.subject); + return createCredentialsWithServicePrincipal( + externalResult.subject, + undefined, + externalResult.accessRestrictions, + ); } throw new AuthenticationError('Illegal token'); diff --git a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts index 96d4ce4dc9..71fbe64963 100644 --- a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts @@ -42,7 +42,26 @@ const mockDeps = [ data: { backend: { baseUrl: 'http://localhost', - auth: { keys: [{ secret: 'abc' }] }, + auth: { + keys: [{ secret: 'abc' }], + externalAccess: [ + { + type: 'static', + options: { + token: 'limited-static-token', + subject: 'limited-static-subject', + }, + accessRestrictions: [{ plugin: 'catalog', permission: 'do.it' }], + }, + { + type: 'static', + options: { + token: 'unlimited-static-token', + subject: 'unlimited-static-subject', + }, + }, + ], + }, }, }, }), @@ -385,4 +404,43 @@ describe('authServiceFactory', () => { "Unable to call 'kubernetes' plugin on behalf of user, because the target plugin does not support on-behalf-of tokens or the plugin doesn't exist", ); }); + + it('should eagerly reject access to external access tokens based on plugin id', async () => { + const tester = ServiceFactoryTester.from(authServiceFactory, { + dependencies: mockDeps, + }); + + const catalogAuth = await tester.get('catalog'); + + await expect( + catalogAuth.authenticate('limited-static-token'), + ).resolves.toMatchObject({ + principal: { + subject: 'limited-static-subject', + accessRestrictions: { permissionNames: ['do.it'] }, + }, + }); + + await expect( + catalogAuth.authenticate('unlimited-static-token'), + ).resolves.toMatchObject({ + principal: { + subject: 'unlimited-static-subject', + }, + }); + + const scaffolderAuth = await tester.get('scaffolder'); + + await expect( + scaffolderAuth.authenticate('limited-static-token'), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"This token's access is restricted to plugin(s) 'catalog'"`, + ); + + await expect( + scaffolderAuth.authenticate('unlimited-static-token'), + ).resolves.toMatchObject({ + principal: { subject: 'unlimited-static-subject' }, + }); + }); }); diff --git a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts index 7bbd012c01..ad4fb17d88 100644 --- a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts @@ -39,19 +39,7 @@ export const authServiceFactory = createServiceFactory({ // new auth services in the new backend system. tokenManager: coreServices.tokenManager, }, - async createRootContext({ config, logger }) { - const externalTokens = ExternalTokenHandler.create({ - config, - logger, - }); - return { - externalTokens, - }; - }, - async factory( - { config, discovery, plugin, tokenManager, logger, database }, - { externalTokens }, - ) { + async factory({ config, discovery, plugin, tokenManager, logger, database }) { const disableDefaultAuthPolicy = Boolean( config.getOptionalBoolean( 'backend.auth.dangerouslyDisableDefaultAuthPolicy', @@ -73,6 +61,11 @@ export const authServiceFactory = createServiceFactory({ publicKeyStore, discovery, }); + const externalTokens = ExternalTokenHandler.create({ + ownPluginId: plugin.getId(), + config, + logger, + }); return new DefaultAuthService( userTokens, diff --git a/packages/backend-app-api/src/services/implementations/auth/external/ExternalTokenHandler.test.ts b/packages/backend-app-api/src/services/implementations/auth/external/ExternalTokenHandler.test.ts new file mode 100644 index 0000000000..559107c59c --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/auth/external/ExternalTokenHandler.test.ts @@ -0,0 +1,211 @@ +/* + * 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 { BackstagePrincipalAccessRestrictions } from '@backstage/backend-plugin-api'; +import { ExternalTokenHandler } from './ExternalTokenHandler'; +import { TokenHandler } from './types'; +import { + mockServices, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; +import { randomBytes } from 'crypto'; +import { SignJWT, exportJWK, generateKeyPair } from 'jose'; +import { DateTime } from 'luxon'; +import { v4 as uuid } from 'uuid'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; + +// Simplified copy of TokenFactory in @backstage/plugin-auth-backend +interface AnyJWK extends Record { + use: 'sig'; + alg: string; + kid: string; + kty: string; +} +class FakeTokenFactory { + private readonly keys = new Array(); + + constructor( + private readonly options: { + issuer: string; + keyDurationSeconds: number; + }, + ) {} + + async issueToken(params: { + claims: { + sub: string; + ent?: string[]; + }; + }): Promise { + const pair = await generateKeyPair('RS256'); + const publicKey = await exportJWK(pair.publicKey); + const kid = uuid(); + publicKey.kid = kid; + this.keys.push(publicKey as AnyJWK); + + const iss = this.options.issuer; + const sub = params.claims.sub; + const ent = params.claims.ent; + const aud = 'backstage'; + const iat = Math.floor(Date.now() / 1000); + const exp = iat + this.options.keyDurationSeconds; + + return new SignJWT({ iss, sub, aud, iat, exp, ent, kid }) + .setProtectedHeader({ alg: 'RS256', ent: ent, kid: kid }) + .setIssuer(iss) + .setAudience(aud) + .setSubject(sub) + .setIssuedAt(iat) + .setExpirationTime(exp) + .sign(pair.privateKey); + } + + async listPublicKeys(): Promise<{ keys: AnyJWK[] }> { + return { keys: this.keys }; + } +} + +describe('ExternalTokenHandler', () => { + const server = setupServer(); + setupRequestMockHandlers(server); + + it('skips over inner handlers that do not match, and applies plugin restrictions', async () => { + const handler1: TokenHandler = { + add: jest.fn(), + verifyToken: jest.fn().mockResolvedValue(undefined), + }; + + const handler2: TokenHandler = { + add: jest.fn(), + verifyToken: jest.fn().mockResolvedValue({ + subject: 'sub', + allAccessRestrictions: new Map( + Object.entries({ + plugin1: { + permissionNames: ['do.it'], + } satisfies BackstagePrincipalAccessRestrictions, + }), + ), + }), + }; + + const plugin1 = new ExternalTokenHandler('plugin1', [handler1, handler2]); + const plugin2 = new ExternalTokenHandler('plugin2', [handler1, handler2]); + + await expect(plugin1.verifyToken('token')).resolves.toEqual({ + subject: 'sub', + accessRestrictions: { permissionNames: ['do.it'] }, + }); + await expect( + plugin2.verifyToken('token'), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"This token's access is restricted to plugin(s) 'plugin1'"`, + ); + }); + + it('successfully parses known methods', async () => { + const legacyKey = randomBytes(24); + + const factory = new FakeTokenFactory({ + issuer: 'blah', + keyDurationSeconds: 100, + }); + + server.use( + rest.get( + 'https://example.com/.well-known/jwks.json', + async (_, res, ctx) => { + const keys = await factory.listPublicKeys(); + return res(ctx.json(keys)); + }, + ), + ); + + const handler = ExternalTokenHandler.create({ + ownPluginId: 'catalog', + logger: mockServices.logger.mock(), + config: mockServices.rootConfig({ + data: { + backend: { + auth: { + externalAccess: [ + { + type: 'legacy', + options: { + secret: legacyKey.toString('base64'), + subject: 'legacy-subject', + }, + accessRestrictions: [ + { plugin: 'catalog', permission: 'catalog.entity.read' }, + ], + }, + { + type: 'static', + options: { + token: 'defdefdef', + subject: 'static-subject', + }, + accessRestrictions: [ + { plugin: 'catalog', permission: 'catalog.entity.read' }, + ], + }, + { + type: 'jwks', + options: { + url: 'https://example.com/.well-known/jwks.json', + algorithm: 'RS256', + issuer: 'blah', + audience: 'backstage', + subjectPrefix: 'custom-prefix', + }, + accessRestrictions: [ + { plugin: 'catalog', permission: 'catalog.entity.read' }, + ], + }, + ], + }, + }, + }, + }), + }); + + const legacyToken = await new SignJWT({ + sub: 'backstage-server', + exp: DateTime.now().plus({ minutes: 1 }).toUnixInteger(), + }) + .setProtectedHeader({ alg: 'HS256' }) + .sign(legacyKey); + + await expect(handler.verifyToken(legacyToken)).resolves.toEqual({ + subject: 'legacy-subject', + accessRestrictions: { permissionNames: ['catalog.entity.read'] }, + }); + + await expect(handler.verifyToken('defdefdef')).resolves.toEqual({ + subject: 'static-subject', + accessRestrictions: { permissionNames: ['catalog.entity.read'] }, + }); + + const jwksToken = await factory.issueToken({ + claims: { sub: 'jwks-subject' }, + }); + await expect(handler.verifyToken(jwksToken)).resolves.toEqual({ + subject: 'external:custom-prefix:jwks-subject', + accessRestrictions: { permissionNames: ['catalog.entity.read'] }, + }); + }); +}); diff --git a/packages/backend-app-api/src/services/implementations/auth/external/ExternalTokenHandler.ts b/packages/backend-app-api/src/services/implementations/auth/external/ExternalTokenHandler.ts index 588a1f1794..72eeae6fcf 100644 --- a/packages/backend-app-api/src/services/implementations/auth/external/ExternalTokenHandler.ts +++ b/packages/backend-app-api/src/services/implementations/auth/external/ExternalTokenHandler.ts @@ -15,15 +15,19 @@ */ import { + BackstagePrincipalAccessRestrictions, LoggerService, RootConfigService, } from '@backstage/backend-plugin-api'; +import { NotAllowedError } from '@backstage/errors'; import { LegacyTokenHandler } from './legacy'; import { StaticTokenHandler } from './static'; +import { JWKSHandler } from './jwks'; import { TokenHandler } from './types'; const NEW_CONFIG_KEY = 'backend.auth.externalAccess'; const OLD_CONFIG_KEY = 'backend.auth.keys'; +let loggedDeprecationWarning = false; /** * Handles all types of external caller token types (i.e. not Backstage user @@ -33,16 +37,19 @@ const OLD_CONFIG_KEY = 'backend.auth.keys'; */ export class ExternalTokenHandler { static create(options: { + ownPluginId: string; config: RootConfigService; logger: LoggerService; }): ExternalTokenHandler { - const { config, logger } = options; + const { ownPluginId, config, logger } = options; const staticHandler = new StaticTokenHandler(); const legacyHandler = new LegacyTokenHandler(); + const jwksHandler = new JWKSHandler(); const handlers: Record = { static: staticHandler, legacy: legacyHandler, + jwks: jwksHandler, }; // Load the new-style handlers @@ -58,12 +65,13 @@ export class ExternalTokenHandler { `Unknown type '${type}' in ${NEW_CONFIG_KEY}, expected one of ${valid}`, ); } - handler.add(handlerConfig.getConfig('options')); + handler.add(handlerConfig); } // Load the old keys too const legacyConfigs = config.getOptionalConfigArray(OLD_CONFIG_KEY) ?? []; - if (legacyConfigs.length) { + if (legacyConfigs.length && !loggedDeprecationWarning) { + loggedDeprecationWarning = true; logger.warn( `DEPRECATION WARNING: The ${OLD_CONFIG_KEY} config has been replaced by ${NEW_CONFIG_KEY}, see https://backstage.io/docs/auth/service-to-service-auth`, ); @@ -72,18 +80,48 @@ export class ExternalTokenHandler { legacyHandler.addOld(handlerConfig); } - return new ExternalTokenHandler(Object.values(handlers)); + return new ExternalTokenHandler(ownPluginId, Object.values(handlers)); } - constructor(private readonly handlers: TokenHandler[]) {} + constructor( + private readonly ownPluginId: string, + private readonly handlers: TokenHandler[], + ) {} - async verifyToken(token: string): Promise<{ subject: string } | undefined> { + async verifyToken(token: string): Promise< + | { + subject: string; + accessRestrictions?: BackstagePrincipalAccessRestrictions; + } + | undefined + > { for (const handler of this.handlers) { const result = await handler.verifyToken(token); if (result) { - return result; + const { allAccessRestrictions, ...rest } = result; + if (allAccessRestrictions) { + const accessRestrictions = allAccessRestrictions.get( + this.ownPluginId, + ); + if (!accessRestrictions) { + const valid = [...allAccessRestrictions.keys()] + .map(k => `'${k}'`) + .join(', '); + throw new NotAllowedError( + `This token's access is restricted to plugin(s) ${valid}`, + ); + } + + return { + ...rest, + accessRestrictions, + }; + } + + return rest; } } + return undefined; } } diff --git a/packages/backend-app-api/src/services/implementations/auth/external/helpers.test.ts b/packages/backend-app-api/src/services/implementations/auth/external/helpers.test.ts new file mode 100644 index 0000000000..5b8e40ed4f --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/auth/external/helpers.test.ts @@ -0,0 +1,247 @@ +/* + * 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 { + readAccessRestrictionsFromConfig, + readStringOrStringArrayFromConfig, +} from './helpers'; +import { JsonObject } from '@backstage/types'; +import { mockServices } from '@backstage/backend-test-utils'; + +describe('readStringOrStringArrayFromConfig', () => { + it('handles all cases correctly', () => { + const config = mockServices.rootConfig({ + data: { + wrongType: 1, + wrongTypeInArray: [1], + singleString: 'a', + spaceSeparatedString: 'a b c', + commaSeparatedString: 'a,b,c', + mixedSeparatorsString: 'a b,c ,, d', + emptyString: '', + emptyArray: [], + simpleArray: ['a', 'b', 'c'], + arrayWithSeparators: ['a b', 'c,d', 'e'], + complexDuplicates: ['a', 'a b', 'a', 'b, a'], + }, + }); + + expect(() => + readStringOrStringArrayFromConfig(config, 'wrongType'), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'wrongType' in 'mock-config', got number, wanted string"`, + ); + expect(() => + readStringOrStringArrayFromConfig(config, 'wrongTypeInArray'), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'wrongTypeInArray[0]' in 'mock-config', got number, wanted string-array"`, + ); + expect(readStringOrStringArrayFromConfig(config, 'singleString')).toEqual([ + 'a', + ]); + expect( + readStringOrStringArrayFromConfig(config, 'spaceSeparatedString'), + ).toEqual(['a', 'b', 'c']); + expect( + readStringOrStringArrayFromConfig(config, 'commaSeparatedString'), + ).toEqual(['a', 'b', 'c']); + expect( + readStringOrStringArrayFromConfig(config, 'mixedSeparatorsString'), + ).toEqual(['a', 'b', 'c', 'd']); + expect(() => + readStringOrStringArrayFromConfig(config, 'emptyString'), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'emptyString' in 'mock-config', got empty-string, wanted string"`, + ); + expect( + readStringOrStringArrayFromConfig(config, 'emptyArray'), + ).toBeUndefined(); + expect(readStringOrStringArrayFromConfig(config, 'simpleArray')).toEqual([ + 'a', + 'b', + 'c', + ]); + expect( + readStringOrStringArrayFromConfig(config, 'arrayWithSeparators'), + ).toEqual(['a', 'b', 'c', 'd', 'e']); + expect( + readStringOrStringArrayFromConfig(config, 'complexDuplicates'), + ).toEqual(['a', 'b']); + }); +}); + +describe('readAccessRestrictionsFromConfig', () => { + function r(config: JsonObject) { + return readAccessRestrictionsFromConfig(new ConfigReader(config)); + } + + it('handles empty / missing restrictions', () => { + expect(r({})).toBeUndefined(); + expect(r({ accessRestrictions: [] })).toBeUndefined(); + }); + + it('handles type errors', () => { + expect(() => + r({ accessRestrictions: 7 }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions' in 'mock-config', got number, wanted object-array"`, + ); + expect(() => + r({ accessRestrictions: ['hello'] }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions[0]' in 'mock-config', got string, wanted object-array"`, + ); + expect(() => + r({ accessRestrictions: [{ unknown: {} }] }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid key 'unknown' in 'accessRestrictions' config, expected one of 'plugin', 'permission', 'permissionAttribute'"`, + ); + expect(() => + r({ accessRestrictions: [{ plugin: 7 }] }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions[0].plugin' in 'mock-config', got number, wanted string"`, + ); + expect(() => + r({ accessRestrictions: [{ plugin: 'valid', permission: 7 }] }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions[0].permission' in 'mock-config', got number, wanted string"`, + ); + expect(() => + r({ accessRestrictions: [{ plugin: 'valid', permission: [7] }] }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions[0].permission[0]' in 'mock-config', got number, wanted string-array"`, + ); + expect(() => + r({ accessRestrictions: [{ plugin: 'valid', permissionAttribute: 7 }] }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions[0].permissionAttribute' in 'mock-config', got number, wanted object"`, + ); + expect(() => + r({ + accessRestrictions: [ + { plugin: 'valid', permissionAttribute: { a: [] } }, + ], + }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid key 'a' in 'permissionAttribute' config, expected 'action'"`, + ); + expect(() => + r({ + accessRestrictions: [ + { plugin: 'valid', permissionAttribute: { action: 7 } }, + ], + }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions[0].permissionAttribute.action' in 'mock-config', got number, wanted string"`, + ); + expect(() => + r({ + accessRestrictions: [ + { plugin: 'valid', permissionAttribute: { action: 'wrong' } }, + ], + }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid value 'wrong' at 'action' in 'permissionAttributes' config, valid values are 'create', 'read', 'update', 'delete'"`, + ); + }); + + it('parses valid access restrictions', () => { + expect( + r({ + accessRestrictions: [ + { + plugin: 'a', + }, + ], + }), + ).toEqual( + new Map( + Object.entries({ + a: {}, + }), + ), + ); + + expect( + r({ + accessRestrictions: [ + { + plugin: 'a', + permission: 'a, b a', + }, + ], + }), + ).toEqual( + new Map( + Object.entries({ + a: { permissionNames: ['a', 'b'] }, + }), + ), + ); + + expect( + r({ + accessRestrictions: [ + { + plugin: 'a', + permission: ['a', 'b', 'a'], + }, + ], + }), + ).toEqual( + new Map( + Object.entries({ + a: { permissionNames: ['a', 'b'] }, + }), + ), + ); + + expect( + r({ + accessRestrictions: [ + { + plugin: 'a', + permissionAttribute: { action: 'read, update read' }, + }, + ], + }), + ).toEqual( + new Map( + Object.entries({ + a: { permissionAttributes: { action: ['read', 'update'] } }, + }), + ), + ); + + expect( + r({ + accessRestrictions: [ + { + plugin: 'a', + permissionAttribute: { action: ['read', 'update', 'read'] }, + }, + ], + }), + ).toEqual( + new Map( + Object.entries({ + a: { permissionAttributes: { action: ['read', 'update'] } }, + }), + ), + ); + }); +}); diff --git a/packages/backend-app-api/src/services/implementations/auth/external/helpers.ts b/packages/backend-app-api/src/services/implementations/auth/external/helpers.ts new file mode 100644 index 0000000000..d6aa0a01ff --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/auth/external/helpers.ts @@ -0,0 +1,149 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; +import { AccessRestriptionsMap } from './types'; + +/** + * Parses and returns the `accessRestrictions` configuration from an + * `externalAccess` entry, or undefined if there wasn't one. + * + * @internal + */ +export function readAccessRestrictionsFromConfig( + externalAccessEntryConfig: Config, +): AccessRestriptionsMap | undefined { + const configs = + externalAccessEntryConfig.getOptionalConfigArray('accessRestrictions') ?? + []; + + const result: AccessRestriptionsMap = new Map(); + for (const config of configs) { + const validKeys = ['plugin', 'permission', 'permissionAttribute']; + for (const key of config.keys()) { + if (!validKeys.includes(key)) { + const valid = validKeys.map(k => `'${k}'`).join(', '); + throw new Error( + `Invalid key '${key}' in 'accessRestrictions' config, expected one of ${valid}`, + ); + } + } + + const pluginId = config.getString('plugin'); + const permissionNames = readPermissionNames(config); + const permissionAttributes = readPermissionAttributes(config); + + if (result.has(pluginId)) { + throw new Error( + `Attempted to declare 'accessRestrictions' twice for plugin '${pluginId}', which is not permitted`, + ); + } + + result.set(pluginId, { + ...(permissionNames ? { permissionNames } : {}), + ...(permissionAttributes ? { permissionAttributes } : {}), + }); + } + + return result.size ? result : undefined; +} + +/** + * Reads a config value as a string or an array of strings, and deduplicates and + * splits by comma/space into a string array. Can also validate against a known + * set of values. Returns undefined if the key didn't exist or if the array + * would have ended up being empty. + * + * @internal + */ +export function readStringOrStringArrayFromConfig( + root: Config, + key: string, + validValues?: readonly T[], +): T[] | undefined { + if (!root.has(key)) { + return undefined; + } + + const rawValues = Array.isArray(root.get(key)) + ? root.getStringArray(key) + : [root.getString(key)]; + + const values = [ + ...new Set( + rawValues + .map(v => v.split(/[ ,]/)) + .flat() + .filter(Boolean), + ), + ]; + + if (!values.length) { + return undefined; + } + + if (validValues?.length) { + for (const value of values) { + if (!validValues.includes(value as T)) { + const valid = validValues.map(k => `'${k}'`).join(', '); + throw new Error( + `Invalid value '${value}' at '${key}' in 'permissionAttributes' config, valid values are ${valid}`, + ); + } + } + } + + return values as T[]; +} + +function readPermissionNames(externalAccessEntryConfig: Config) { + return readStringOrStringArrayFromConfig( + externalAccessEntryConfig, + 'permission', + ); +} + +function readPermissionAttributes(externalAccessEntryConfig: Config) { + const config = externalAccessEntryConfig.getOptionalConfig( + 'permissionAttribute', + ); + if (!config) { + return undefined; + } + + const validKeys = ['action']; + for (const key of config.keys()) { + if (!validKeys.includes(key)) { + const valid = validKeys.map(k => `'${k}'`).join(', '); + throw new Error( + `Invalid key '${key}' in 'permissionAttribute' config, expected ${valid}`, + ); + } + } + + const action = readStringOrStringArrayFromConfig(config, 'action', [ + 'create', + 'read', + 'update', + 'delete', + ]); + + const result = { + ...(action ? { action } : {}), + }; + + return Object.keys(result).length ? result : undefined; +} diff --git a/packages/backend-app-api/src/services/implementations/auth/external/jwks.test.ts b/packages/backend-app-api/src/services/implementations/auth/external/jwks.test.ts new file mode 100644 index 0000000000..56930e4480 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/auth/external/jwks.test.ts @@ -0,0 +1,261 @@ +/* + * 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 { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { SignJWT, exportJWK, generateKeyPair } from 'jose'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { v4 as uuid } from 'uuid'; +import { JWKSHandler } from './jwks'; + +// Simplified copy of TokenFactory in @backstage/plugin-auth-backend +interface AnyJWK extends Record { + use: 'sig'; + alg: string; + kid: string; + kty: string; +} +class FakeTokenFactory { + private readonly keys = new Array(); + + constructor( + private readonly options: { + issuer: string; + keyDurationSeconds: number; + }, + ) {} + + async issueToken(params: { + claims: { + sub: string; + ent?: string[]; + }; + }): Promise { + const pair = await generateKeyPair('RS256'); + const publicKey = await exportJWK(pair.publicKey); + const kid = uuid(); + publicKey.kid = kid; + this.keys.push(publicKey as AnyJWK); + + const iss = this.options.issuer; + const sub = params.claims.sub; + const ent = params.claims.ent; + const aud = 'backstage'; + const iat = Math.floor(Date.now() / 1000); + const exp = iat + this.options.keyDurationSeconds; + + return new SignJWT({ iss, sub, aud, iat, exp, ent, kid }) + .setProtectedHeader({ alg: 'RS256', ent: ent, kid: kid }) + .setIssuer(iss) + .setAudience(aud) + .setSubject(sub) + .setIssuedAt(iat) + .setExpirationTime(exp) + .sign(pair.privateKey); + } + + async listPublicKeys(): Promise<{ keys: AnyJWK[] }> { + return { keys: this.keys }; + } +} + +const server = setupServer(); +const mockBaseUrl = 'http://backstage:9191/i-am-a-mock-base'; + +describe('JWKSHandler', () => { + let factory: FakeTokenFactory; + let mockSubject: string; + const keyDurationSeconds = 5; + + setupRequestMockHandlers(server); + + beforeEach(() => { + mockSubject = 'test_subject'; + + factory = new FakeTokenFactory({ + issuer: mockBaseUrl, + keyDurationSeconds, + }); + + server.use( + rest.get(`${mockBaseUrl}/.well-known/jwks.json`, async (_, res, ctx) => { + const keys = await factory.listPublicKeys(); + return res(ctx.json(keys)); + }), + ); + }); + + it('verifies token with valid entry', async () => { + const validEntry = { + options: { + url: `${mockBaseUrl}/.well-known/jwks.json`, + algorithm: 'RS256', + issuer: mockBaseUrl, + audience: 'backstage', + }, + }; + const jwksHandler = new JWKSHandler(); + + jwksHandler.add(new ConfigReader(validEntry)); + + const token = await factory.issueToken({ + claims: { sub: mockSubject }, + }); + + const result = await jwksHandler.verifyToken(token); + + expect(result).toEqual({ subject: `external:${mockSubject}` }); + }); + + it('skips invalid entry and continues verification', async () => { + const invalidEntry = { + options: { + url: `${mockBaseUrl}/.well-known/jwks.json`, + algorithm: 'RS256', + issuer: ['fakeIssuer'], + audience: ['fakeAud'], + }, + }; + + const validEntry = { + options: { + url: `${mockBaseUrl}/.well-known/jwks.json`, + algorithm: 'RS256', + issuer: ['multiple-issuers', mockBaseUrl], + audience: ['multiple-audiences', 'backstage'], + }, + }; + const jwksHandler = new JWKSHandler(); + + jwksHandler.add(new ConfigReader(invalidEntry)); + jwksHandler.add(new ConfigReader(validEntry)); + + const token = await factory.issueToken({ + claims: { sub: mockSubject }, + }); + + const result = await jwksHandler.verifyToken(token); + + expect(result).toEqual({ subject: `external:${mockSubject}` }); + }); + + it('returns undefined if no valid entry found', async () => { + const invalidEntry1 = { + options: { + url: `${mockBaseUrl}/.well-known/jwks.json`, + algorithm: 'RS256', + issuer: 'wrong', + }, + }; + + const invalidEntry2 = { + options: { + url: `${mockBaseUrl}/.well-known/jwks.json`, + algorithm: ['HS256'], + audience: 'wrong', + }, + }; + const jwksHandler = new JWKSHandler(); + + jwksHandler.add(new ConfigReader(invalidEntry1)); + jwksHandler.add(new ConfigReader(invalidEntry2)); + + const token = await factory.issueToken({ + claims: { sub: mockSubject }, + }); + + const result = await jwksHandler.verifyToken(token); + + expect(result).toBeUndefined(); + }); + + it('rejects bad config', () => { + const jwksHandler = new JWKSHandler(); + + expect(() => { + jwksHandler.add( + new ConfigReader({ + options: { + url: 'https://exampl e.com/jwks', + }, + }), + ); + }).toThrow('Illegal JWKS URL, must be a set of non-space characters'); + expect(() => { + jwksHandler.add( + new ConfigReader({ + options: { + url: 'https://example.com/jwks\n', + }, + }), + ); + }).toThrow('Illegal JWKS URL, must be a set of non-space characters'); + }); + + it('gracefully handles no added tokens', async () => { + const handler = new JWKSHandler(); + await expect(handler.verifyToken('ghi')).resolves.toBeUndefined(); + }); + + it('uses custom subject prefix if provided', async () => { + const validEntry = { + options: { + url: `${mockBaseUrl}/.well-known/jwks.json`, + algorithm: 'RS256', + issuer: mockBaseUrl, + audience: 'backstage', + subjectPrefix: 'custom-prefix', + }, + }; + const jwksHandler = new JWKSHandler(); + + jwksHandler.add(new ConfigReader(validEntry)); + + const token = await factory.issueToken({ + claims: { sub: mockSubject }, + }); + + const result = await jwksHandler.verifyToken(token); + + expect(result).toEqual({ + subject: `external:${validEntry.options.subjectPrefix}:${mockSubject}`, + }); + }); + + it('carries over access restrictions', async () => { + const jwksHandler = new JWKSHandler(); + jwksHandler.add( + new ConfigReader({ + options: { + url: `${mockBaseUrl}/.well-known/jwks.json`, + }, + accessRestrictions: [{ plugin: 'scaffolder', permission: 'do.it' }], + }), + ); + + const token = await factory.issueToken({ claims: { sub: mockSubject } }); + + await expect(jwksHandler.verifyToken(token)).resolves.toEqual({ + subject: `external:${mockSubject}`, + allAccessRestrictions: new Map( + Object.entries({ + scaffolder: { permissionNames: ['do.it'] }, + }), + ), + }); + }); +}); diff --git a/packages/backend-app-api/src/services/implementations/auth/external/jwks.ts b/packages/backend-app-api/src/services/implementations/auth/external/jwks.ts new file mode 100644 index 0000000000..d88dc62a47 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/auth/external/jwks.ts @@ -0,0 +1,99 @@ +/* + * 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 { jwtVerify, createRemoteJWKSet, JWTVerifyGetKey } from 'jose'; +import { Config } from '@backstage/config'; +import { + readAccessRestrictionsFromConfig, + readStringOrStringArrayFromConfig, +} from './helpers'; +import { AccessRestriptionsMap, TokenHandler } from './types'; + +/** + * Handles `type: jwks` access. + * + * @internal + */ +export class JWKSHandler implements TokenHandler { + #entries: Array<{ + algorithms?: string[]; + audiences?: string[]; + issuers?: string[]; + subjectPrefix?: string; + url: URL; + jwks: JWTVerifyGetKey; + allAccessRestrictions?: AccessRestriptionsMap; + }> = []; + + add(config: Config) { + if (!config.getString('options.url').match(/^\S+$/)) { + throw new Error( + 'Illegal JWKS URL, must be a set of non-space characters', + ); + } + + const algorithms = readStringOrStringArrayFromConfig( + config, + 'options.algorithm', + ); + const issuers = readStringOrStringArrayFromConfig(config, 'options.issuer'); + const audiences = readStringOrStringArrayFromConfig( + config, + 'options.audience', + ); + const subjectPrefix = config.getOptionalString('options.subjectPrefix'); + const url = new URL(config.getString('options.url')); + const jwks = createRemoteJWKSet(url); + const allAccessRestrictions = readAccessRestrictionsFromConfig(config); + + this.#entries.push({ + algorithms, + audiences, + issuers, + jwks, + subjectPrefix, + url, + allAccessRestrictions, + }); + } + + async verifyToken(token: string) { + for (const entry of this.#entries) { + try { + const { + payload: { sub }, + } = await jwtVerify(token, entry.jwks, { + algorithms: entry.algorithms, + issuer: entry.issuers, + audience: entry.audiences, + }); + + if (sub) { + const prefix = entry.subjectPrefix + ? `external:${entry.subjectPrefix}:` + : 'external:'; + return { + subject: `${prefix}${sub}`, + allAccessRestrictions: entry.allAccessRestrictions, + }; + } + } catch { + continue; + } + } + return undefined; + } +} diff --git a/packages/backend-app-api/src/services/implementations/auth/external/legacy.test.ts b/packages/backend-app-api/src/services/implementations/auth/external/legacy.test.ts index 8b2469f6b7..c674e46ec9 100644 --- a/packages/backend-app-api/src/services/implementations/auth/external/legacy.test.ts +++ b/packages/backend-app-api/src/services/implementations/auth/external/legacy.test.ts @@ -25,17 +25,35 @@ describe('LegacyTokenHandler', () => { const key1 = randomBytes(24); const key2 = randomBytes(24); const key3 = randomBytes(24); + const accessRestrictions1 = new Map( + Object.entries({ + scaffolder: {}, + }), + ); + const accessRestrictions2 = new Map( + Object.entries({ + catalog: { permissionNames: ['catalog.entity.read'] }, + }), + ); tokenHandler.add( new ConfigReader({ - secret: key1.toString('base64'), - subject: 'key1', + options: { + secret: key1.toString('base64'), + subject: 'key1', + }, + accessRestrictions: [{ plugin: 'scaffolder' }], }), ); tokenHandler.add( new ConfigReader({ - secret: key2.toString('base64'), - subject: 'key2', + options: { + secret: key2.toString('base64'), + subject: 'key2', + }, + accessRestrictions: [ + { plugin: 'catalog', permission: 'catalog.entity.read' }, + ], }), ); tokenHandler.addOld( @@ -54,6 +72,7 @@ describe('LegacyTokenHandler', () => { await expect(tokenHandler.verifyToken(token1)).resolves.toEqual({ subject: 'key1', + allAccessRestrictions: accessRestrictions1, }); const token2 = await new SignJWT({ @@ -65,6 +84,7 @@ describe('LegacyTokenHandler', () => { await expect(tokenHandler.verifyToken(token2)).resolves.toEqual({ subject: 'key2', + allAccessRestrictions: accessRestrictions2, }); const token3 = await new SignJWT({ @@ -147,39 +167,93 @@ describe('LegacyTokenHandler', () => { // new style add, bad secrets expect(() => - handler.add(new ConfigReader({ _missingsecret: true, subject: 'ok' })), - ).toThrow(/secret/); + handler.add( + new ConfigReader({ options: { _missingsecret: true, subject: 'ok' } }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Missing required config value at 'options.secret' in 'mock-config'"`, + ); expect(() => - handler.add(new ConfigReader({ secret: '', subject: 'ok' })), - ).toThrow(/secret/); + handler.add(new ConfigReader({ options: { secret: '', subject: 'ok' } })), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'options.secret' in 'mock-config', got empty-string, wanted string"`, + ); expect(() => - handler.add(new ConfigReader({ secret: 'has spaces', subject: 'ok' })), - ).toThrow(/secret/); + handler.add( + new ConfigReader({ options: { secret: 'has spaces', subject: 'ok' } }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Illegal secret, must be a valid base64 string"`, + ); expect(() => - handler.add(new ConfigReader({ secret: 'hasnewline\n', subject: 'ok' })), - ).toThrow(/secret/); + handler.add( + new ConfigReader({ + options: { secret: 'hasnewline\n', subject: 'ok' }, + }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Illegal secret, must be a valid base64 string"`, + ); expect(() => - handler.add(new ConfigReader({ secret: 3, subject: 'ok' })), - ).toThrow(/secret/); + handler.add(new ConfigReader({ options: { secret: 3, subject: 'ok' } })), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'options.secret' in 'mock-config', got number, wanted string"`, + ); // new style add, bad subjects expect(() => - handler.add(new ConfigReader({ secret: 'b2s=', _missingsubject: true })), - ).toThrow(/subject/); - expect(() => - handler.add(new ConfigReader({ secret: 'b2s=', subject: '' })), - ).toThrow(/subject/); - expect(() => - handler.add(new ConfigReader({ secret: 'b2s=', subject: 'has spaces' })), - ).toThrow(/subject/); + handler.add( + new ConfigReader({ + options: { secret: 'b2s=', _missingsubject: true }, + }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Missing required config value at 'options.subject' in 'mock-config'"`, + ); expect(() => handler.add( - new ConfigReader({ secret: 'b2s=', subject: 'hasnewline\n' }), + new ConfigReader({ options: { secret: 'b2s=', subject: '' } }), ), - ).toThrow(/subject/); + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'options.subject' in 'mock-config', got empty-string, wanted string"`, + ); expect(() => - handler.add(new ConfigReader({ secret: 'b2s=', subject: 3 })), - ).toThrow(/subject/); + handler.add( + new ConfigReader({ + options: { secret: 'b2s=', subject: 'has spaces' }, + }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Illegal subject, must be a set of non-space characters"`, + ); + expect(() => + handler.add( + new ConfigReader({ + options: { secret: 'b2s=', subject: 'hasnewline\n' }, + }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Illegal subject, must be a set of non-space characters"`, + ); + expect(() => + handler.add( + new ConfigReader({ options: { secret: 'b2s=', subject: 3 } }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'options.subject' in 'mock-config', got number, wanted string"`, + ); + + // new style add, bad access restrictions + expect(() => + handler.add( + new ConfigReader({ + options: { secret: 'b2s=', subject: 'subject' }, + accessRestrictions: [{ plugin: ['a'] }], + }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'accessRestrictions[0].plugin' in 'mock-config', got array, wanted string"`, + ); // old style add expect(() => @@ -187,18 +261,28 @@ describe('LegacyTokenHandler', () => { ).not.toThrow(); expect(() => handler.addOld(new ConfigReader({ _missingsecret: true })), - ).toThrow(/secret/); - expect(() => handler.addOld(new ConfigReader({ secret: '' }))).toThrow( - /secret/, + ).toThrowErrorMatchingInlineSnapshot( + `"Missing required config value at 'secret' in 'mock-config'"`, + ); + expect(() => + handler.addOld(new ConfigReader({ secret: '' })), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'secret' in 'mock-config', got empty-string, wanted string"`, ); expect(() => handler.addOld(new ConfigReader({ secret: 'has spaces' })), - ).toThrow(/secret/); + ).toThrowErrorMatchingInlineSnapshot( + `"Illegal secret, must be a valid base64 string"`, + ); expect(() => handler.addOld(new ConfigReader({ secret: 'hasnewline\n' })), - ).toThrow(/secret/); - expect(() => handler.addOld(new ConfigReader({ secret: 3 }))).toThrow( - /secret/, + ).toThrowErrorMatchingInlineSnapshot( + `"Illegal secret, must be a valid base64 string"`, + ); + expect(() => + handler.addOld(new ConfigReader({ secret: 3 })), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'secret' in 'mock-config', got number, wanted string"`, ); }); }); diff --git a/packages/backend-app-api/src/services/implementations/auth/external/legacy.ts b/packages/backend-app-api/src/services/implementations/auth/external/legacy.ts index 8448f295a6..9c60e70707 100644 --- a/packages/backend-app-api/src/services/implementations/auth/external/legacy.ts +++ b/packages/backend-app-api/src/services/implementations/auth/external/legacy.ts @@ -16,7 +16,8 @@ import { Config } from '@backstage/config'; import { base64url, decodeJwt, decodeProtectedHeader, jwtVerify } from 'jose'; -import { TokenHandler } from './types'; +import { readAccessRestrictionsFromConfig } from './helpers'; +import { AccessRestriptionsMap, TokenHandler } from './types'; /** * Handles `type: legacy` access. @@ -24,21 +25,38 @@ import { TokenHandler } from './types'; * @internal */ export class LegacyTokenHandler implements TokenHandler { - #entries: Array<{ key: Uint8Array; subject: string }> = []; + #entries = new Array<{ + key: Uint8Array; + result: { + subject: string; + allAccessRestrictions?: AccessRestriptionsMap; + }; + }>(); - add(options: Config) { - this.#doAdd(options.getString('secret'), options.getString('subject')); + add(config: Config) { + const allAccessRestrictions = readAccessRestrictionsFromConfig(config); + this.#doAdd( + config.getString('options.secret'), + config.getString('options.subject'), + allAccessRestrictions, + ); } // used only for the old backend.auth.keys array - addOld(options: Config) { + addOld(config: Config) { // This choice of subject is for compatibility reasons - this.#doAdd(options.getString('secret'), 'external:backstage-plugin'); + this.#doAdd(config.getString('secret'), 'external:backstage-plugin'); } - #doAdd(secret: string, subject: string) { + #doAdd( + secret: string, + subject: string, + allAccessRestrictions?: AccessRestriptionsMap, + ) { if (!secret.match(/^\S+$/)) { throw new Error('Illegal secret, must be a valid base64 string'); + } else if (!subject.match(/^\S+$/)) { + throw new Error('Illegal subject, must be a set of non-space characters'); } let key: Uint8Array; @@ -48,11 +66,19 @@ export class LegacyTokenHandler implements TokenHandler { throw new Error('Illegal secret, must be a valid base64 string'); } - if (!subject.match(/^\S+$/)) { - throw new Error('Illegal subject, must be a set of non-space characters'); + if (this.#entries.some(e => e.key === key)) { + throw new Error( + 'Legacy externalAccess token was declared more than once', + ); } - this.#entries.push({ key, subject }); + this.#entries.push({ + key, + result: { + subject, + allAccessRestrictions, + }, + }); } async verifyToken(token: string) { @@ -76,10 +102,10 @@ export class LegacyTokenHandler implements TokenHandler { return undefined; } - for (const entry of this.#entries) { + for (const { key, result } of this.#entries) { try { - await jwtVerify(token, entry.key); - return { subject: entry.subject }; + await jwtVerify(token, key); + return result; } catch (e) { if (e.code !== 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED') { throw e; diff --git a/packages/backend-app-api/src/services/implementations/auth/external/static.test.ts b/packages/backend-app-api/src/services/implementations/auth/external/static.test.ts index 86bdf0bdee..a5945daba9 100644 --- a/packages/backend-app-api/src/services/implementations/auth/external/static.test.ts +++ b/packages/backend-app-api/src/services/implementations/auth/external/static.test.ts @@ -20,14 +20,36 @@ import { StaticTokenHandler } from './static'; describe('StaticTokenHandler', () => { it('accepts any of the added list of tokens', async () => { const handler = new StaticTokenHandler(); - handler.add(new ConfigReader({ token: 'abcabcabc', subject: 'one' })); - handler.add(new ConfigReader({ token: 'defdefdef', subject: 'two' })); + handler.add( + new ConfigReader({ + options: { token: 'abcabcabc', subject: 'one' }, + accessRestrictions: [{ plugin: 'scaffolder' }], + }), + ); + handler.add( + new ConfigReader({ + options: { token: 'defdefdef', subject: 'two' }, + accessRestrictions: [ + { plugin: 'catalog', permission: 'catalog.entity.read' }, + ], + }), + ); + const accessRestrictionsOne = new Map(Object.entries({ scaffolder: {} })); + const accessRestrictionsTwo = new Map( + Object.entries({ + catalog: { + permissionNames: ['catalog.entity.read'], + }, + }), + ); await expect(handler.verifyToken('abcabcabc')).resolves.toEqual({ subject: 'one', + allAccessRestrictions: accessRestrictionsOne, }); await expect(handler.verifyToken('defdefdef')).resolves.toEqual({ subject: 'two', + allAccessRestrictions: accessRestrictionsTwo, }); await expect(handler.verifyToken('ghighighi')).resolves.toBeUndefined(); }); @@ -41,71 +63,89 @@ describe('StaticTokenHandler', () => { const handler = new StaticTokenHandler(); expect(() => - handler.add(new ConfigReader({ _missingtoken: true, subject: 'ok' })), + handler.add( + new ConfigReader({ options: { _missingtoken: true, subject: 'ok' } }), + ), ).toThrowErrorMatchingInlineSnapshot( - `"Missing required config value at 'token' in 'mock-config'"`, + `"Missing required config value at 'options.token' in 'mock-config'"`, ); expect(() => - handler.add(new ConfigReader({ token: '', subject: 'ok' })), + handler.add(new ConfigReader({ options: { token: '', subject: 'ok' } })), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid type in config for key 'token' in 'mock-config', got empty-string, wanted string"`, + `"Invalid type in config for key 'options.token' in 'mock-config', got empty-string, wanted string"`, ); expect(() => - handler.add(new ConfigReader({ token: 'has spaces', subject: 'ok' })), + handler.add( + new ConfigReader({ options: { token: 'has spaces', subject: 'ok' } }), + ), ).toThrowErrorMatchingInlineSnapshot( `"Illegal token, must be a set of non-space characters"`, ); expect(() => handler.add( new ConfigReader({ - token: 'hasnewlinebutislongenough\n', - subject: 'ok', + options: { + token: 'hasnewlinebutislongenough\n', + subject: 'ok', + }, }), ), ).toThrowErrorMatchingInlineSnapshot( `"Illegal token, must be a set of non-space characters"`, ); expect(() => - handler.add(new ConfigReader({ token: 'short', subject: 'ok' })), + handler.add( + new ConfigReader({ options: { token: 'short', subject: 'ok' } }), + ), ).toThrowErrorMatchingInlineSnapshot( `"Illegal token, must be at least 8 characters length"`, ); expect(() => - handler.add(new ConfigReader({ token: 3, subject: 'ok' })), + handler.add(new ConfigReader({ options: { token: 3, subject: 'ok' } })), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid type in config for key 'token' in 'mock-config', got number, wanted string"`, + `"Invalid type in config for key 'options.token' in 'mock-config', got number, wanted string"`, ); expect(() => handler.add( - new ConfigReader({ token: 'validtoken', _missingsubject: true }), + new ConfigReader({ + options: { token: 'validtoken', _missingsubject: true }, + }), ), ).toThrowErrorMatchingInlineSnapshot( - `"Missing required config value at 'subject' in 'mock-config'"`, - ); - expect(() => - handler.add(new ConfigReader({ token: 'validtoken', subject: '' })), - ).toThrowErrorMatchingInlineSnapshot( - `"Invalid type in config for key 'subject' in 'mock-config', got empty-string, wanted string"`, + `"Missing required config value at 'options.subject' in 'mock-config'"`, ); expect(() => handler.add( - new ConfigReader({ token: 'validtoken', subject: 'has spaces' }), + new ConfigReader({ options: { token: 'validtoken', subject: '' } }), + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'options.subject' in 'mock-config', got empty-string, wanted string"`, + ); + expect(() => + handler.add( + new ConfigReader({ + options: { token: 'validtoken', subject: 'has spaces' }, + }), ), ).toThrowErrorMatchingInlineSnapshot( `"Illegal subject, must be a set of non-space characters"`, ); expect(() => handler.add( - new ConfigReader({ token: 'validtoken', subject: 'hasnewline\n' }), + new ConfigReader({ + options: { token: 'validtoken', subject: 'hasnewline\n' }, + }), ), ).toThrowErrorMatchingInlineSnapshot( `"Illegal subject, must be a set of non-space characters"`, ); expect(() => - handler.add(new ConfigReader({ token: 'validtoken', subject: 3 })), + handler.add( + new ConfigReader({ options: { token: 'validtoken', subject: 3 } }), + ), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid type in config for key 'subject' in 'mock-config', got number, wanted string"`, + `"Invalid type in config for key 'options.subject' in 'mock-config', got number, wanted string"`, ); }); }); diff --git a/packages/backend-app-api/src/services/implementations/auth/external/static.ts b/packages/backend-app-api/src/services/implementations/auth/external/static.ts index bae8e05f2b..1e89d8c6a1 100644 --- a/packages/backend-app-api/src/services/implementations/auth/external/static.ts +++ b/packages/backend-app-api/src/services/implementations/auth/external/static.ts @@ -15,7 +15,8 @@ */ import { Config } from '@backstage/config'; -import { TokenHandler } from './types'; +import { readAccessRestrictionsFromConfig } from './helpers'; +import { AccessRestriptionsMap, TokenHandler } from './types'; const MIN_TOKEN_LENGTH = 8; @@ -25,33 +26,37 @@ const MIN_TOKEN_LENGTH = 8; * @internal */ export class StaticTokenHandler implements TokenHandler { - #entries: Array<{ token: string; subject: string }> = []; + #entries = new Map< + string, + { + subject: string; + allAccessRestrictions?: AccessRestriptionsMap; + } + >(); + + add(config: Config) { + const token = config.getString('options.token'); + const subject = config.getString('options.subject'); + const allAccessRestrictions = readAccessRestrictionsFromConfig(config); - add(options: Config) { - const token = options.getString('token'); if (!token.match(/^\S+$/)) { throw new Error('Illegal token, must be a set of non-space characters'); - } - if (token.length < MIN_TOKEN_LENGTH) { + } else if (token.length < MIN_TOKEN_LENGTH) { throw new Error( `Illegal token, must be at least ${MIN_TOKEN_LENGTH} characters length`, ); - } - - const subject = options.getString('subject'); - if (!subject.match(/^\S+$/)) { + } else if (!subject.match(/^\S+$/)) { throw new Error('Illegal subject, must be a set of non-space characters'); + } else if (this.#entries.has(token)) { + throw new Error( + 'Static externalAccess token was declared more than once', + ); } - this.#entries.push({ token, subject }); + this.#entries.set(token, { subject, allAccessRestrictions }); } async verifyToken(token: string) { - const entry = this.#entries.find(e => e.token === token); - if (!entry) { - return undefined; - } - - return { subject: entry.subject }; + return this.#entries.get(token); } } diff --git a/packages/backend-app-api/src/services/implementations/auth/external/types.ts b/packages/backend-app-api/src/services/implementations/auth/external/types.ts index 5d33f09a22..6a1fd084ed 100644 --- a/packages/backend-app-api/src/services/implementations/auth/external/types.ts +++ b/packages/backend-app-api/src/services/implementations/auth/external/types.ts @@ -14,9 +14,21 @@ * limitations under the License. */ +import { BackstagePrincipalAccessRestrictions } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; +export type AccessRestriptionsMap = Map< + string, // plugin ID + BackstagePrincipalAccessRestrictions +>; + export interface TokenHandler { add(options: Config): void; - verifyToken(token: string): Promise<{ subject: string } | undefined>; + verifyToken(token: string): Promise< + | { + subject: string; + allAccessRestrictions?: AccessRestriptionsMap; + } + | undefined + >; } diff --git a/packages/backend-app-api/src/services/implementations/auth/helpers.ts b/packages/backend-app-api/src/services/implementations/auth/helpers.ts index 01fb9537a1..eebe45eb76 100644 --- a/packages/backend-app-api/src/services/implementations/auth/helpers.ts +++ b/packages/backend-app-api/src/services/implementations/auth/helpers.ts @@ -17,6 +17,7 @@ import { BackstageCredentials, BackstageNonePrincipal, + BackstagePrincipalAccessRestrictions, BackstageServicePrincipal, BackstageUserPrincipal, } from '@backstage/backend-plugin-api'; @@ -25,6 +26,7 @@ import { InternalBackstageCredentials } from './types'; export function createCredentialsWithServicePrincipal( sub: string, token?: string, + accessRestrictions?: BackstagePrincipalAccessRestrictions, ): InternalBackstageCredentials { return { $$type: '@backstage/BackstageCredentials', @@ -33,6 +35,7 @@ export function createCredentialsWithServicePrincipal( principal: { type: 'service', subject: sub, + accessRestrictions, }, }; } diff --git a/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.test.ts b/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.test.ts index f2a86e4a20..b0e8418655 100644 --- a/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.test.ts +++ b/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.test.ts @@ -133,6 +133,34 @@ describe('UserTokenHandler', () => { ).rejects.toThrow('signature verification failed'); }); + it('should fail to verify tokens that have a bad alg', async () => { + const expectedIssuedAt = 1712071714; + const expectedExpiresAt = 1712075314; + + jest.useFakeTimers({ + now: expectedIssuedAt * 1000 + 600_000, + }); + + const header = encodeData({ + typ: 'vnd.backstage.user', + alg: 'none', + }); + const payload = encodeData({ + iss: 'http://localhost:7007/api/auth', + sub: 'user:development/guest', + ent: ['user:development/guest', 'group:default/team-a'], + aud: 'backstage', + iat: expectedIssuedAt, + exp: expectedExpiresAt, + uip: 'proof', + }); + const token = `${header}.${payload}.`; + + await expect(userTokenHandler.verifyToken(token)).rejects.toThrow( + /Unsupported "alg" value/, + ); + }); + it('should verify a valid legacy backstage token', async () => { const expectedIssuedAt = 1712071714; const expectedExpiresAt = 1712075314; @@ -151,7 +179,7 @@ describe('UserTokenHandler', () => { sub: 'user:development/guest', ent: ['user:development/guest', 'group:default/team-a'], aud: 'backstage', - iat: 1712071714, + iat: expectedIssuedAt, exp: expectedExpiresAt, }, }; @@ -179,7 +207,7 @@ describe('UserTokenHandler', () => { iss: 'http://localhost:7007/api/auth', ent: ['user:development/guest', 'group:default/team-a'], aud: 'backstage', - iat: 1712071714, + iat: expectedIssuedAt, exp: expectedExpiresAt, }, }; @@ -209,7 +237,7 @@ describe('UserTokenHandler', () => { sub: 'user:development/guest', ent: ['user:development/guest', 'group:default/team-a'], aud: 'backstage', - iat: 1712071714, + iat: expectedIssuedAt, exp: expectedExpiresAt, uip: 'proof', }, @@ -239,7 +267,7 @@ describe('UserTokenHandler', () => { payload: { sub: 'user:development/guest', ent: ['user:development/guest', 'group:default/team-a'], - iat: 1712071714, + iat: expectedIssuedAt, exp: expectedExpiresAt, }, }; diff --git a/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.ts b/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.ts index af3faae22d..bd73d8701f 100644 --- a/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.ts +++ b/packages/backend-app-api/src/services/implementations/auth/user/UserTokenHandler.ts @@ -34,18 +34,14 @@ import { JwksClient } from '../JwksClient'; */ export class UserTokenHandler { static create(options: { discovery: DiscoveryService }): UserTokenHandler { - const algorithms = ['ES256']; // TODO: configurable? const jwksClient = new JwksClient(async () => { const url = await options.discovery.getBaseUrl('auth'); return new URL(`${url}/.well-known/jwks.json`); }); - return new UserTokenHandler(algorithms, jwksClient); + return new UserTokenHandler(jwksClient); } - constructor( - private readonly algorithms: string[], - private readonly jwksClient: JwksClient, - ) {} + constructor(private readonly jwksClient: JwksClient) {} async verifyToken(token: string) { const verifyOpts = this.#getTokenVerificationOptions(token); @@ -79,7 +75,6 @@ export class UserTokenHandler { if (typ === tokenTypes.user.typParam) { return { - algorithms: this.algorithms, requiredClaims: ['iat', 'exp', 'sub'], typ: tokenTypes.user.typParam, }; @@ -87,7 +82,6 @@ export class UserTokenHandler { if (typ === tokenTypes.limitedUser.typParam) { return { - algorithms: this.algorithms, requiredClaims: ['iat', 'exp', 'sub'], typ: tokenTypes.limitedUser.typParam, }; @@ -96,7 +90,6 @@ export class UserTokenHandler { const { aud } = decodeJwt(token); if (aud === tokenTypes.user.audClaim) { return { - algorithms: this.algorithms, audience: tokenTypes.user.audClaim, }; } diff --git a/packages/backend-app-api/src/services/implementations/cache/cacheServiceFactory.ts b/packages/backend-app-api/src/services/implementations/cache/cacheServiceFactory.ts index b91356a13a..9b5e5ab16a 100644 --- a/packages/backend-app-api/src/services/implementations/cache/cacheServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/cache/cacheServiceFactory.ts @@ -20,15 +20,19 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/cache` instead. + */ export const cacheServiceFactory = createServiceFactory({ service: coreServices.cache, deps: { config: coreServices.rootConfig, + logger: coreServices.rootLogger, plugin: coreServices.pluginMetadata, }, - async createRootContext({ config }) { - return CacheManager.fromConfig(config); + async createRootContext({ config, logger }) { + return CacheManager.fromConfig(config, { logger }); }, async factory({ plugin }, manager) { return manager.forPlugin(plugin.getId()).getClient(); diff --git a/packages/backend-app-api/src/services/implementations/config/rootConfigServiceFactory.ts b/packages/backend-app-api/src/services/implementations/config/rootConfigServiceFactory.ts index 68103842bb..c74474e629 100644 --- a/packages/backend-app-api/src/services/implementations/config/rootConfigServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/config/rootConfigServiceFactory.ts @@ -23,7 +23,10 @@ import { RemoteConfigSourceOptions, } from '@backstage/config-loader'; -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/rootConfig` instead. + */ export interface RootConfigFactoryOptions { /** * Process arguments to use instead of the default `process.argv()`. @@ -37,7 +40,10 @@ export interface RootConfigFactoryOptions { watch?: boolean; } -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/rootConfig` instead. + */ export const rootConfigServiceFactory = createServiceFactory( (options?: RootConfigFactoryOptions) => ({ service: coreServices.rootConfig, diff --git a/packages/backend-app-api/src/services/implementations/database/databaseServiceFactory.ts b/packages/backend-app-api/src/services/implementations/database/databaseServiceFactory.ts index 139609b6c1..972d8dd4ec 100644 --- a/packages/backend-app-api/src/services/implementations/database/databaseServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/database/databaseServiceFactory.ts @@ -21,7 +21,10 @@ import { } from '@backstage/backend-plugin-api'; import { ConfigReader } from '@backstage/config'; -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/database` instead. + */ export const databaseServiceFactory = createServiceFactory({ service: coreServices.database, deps: { diff --git a/plugins/catalog-backend/src/ingestion/index.ts b/packages/backend-app-api/src/services/implementations/deprecated.ts similarity index 86% rename from plugins/catalog-backend/src/ingestion/index.ts rename to packages/backend-app-api/src/services/implementations/deprecated.ts index a6555dd98d..6f4f76e679 100644 --- a/plugins/catalog-backend/src/ingestion/index.ts +++ b/packages/backend-app-api/src/services/implementations/deprecated.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,4 +14,4 @@ * limitations under the License. */ -export type { LocationAnalyzer } from './types'; +export * from './scheduler'; diff --git a/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.ts b/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.ts index 180c8706d5..d337da997a 100644 --- a/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.ts +++ b/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.ts @@ -29,6 +29,7 @@ type Target = string | { internal: string; external: string }; * resolved to the same host, so there won't be any balancing of internal traffic. * * @public + * @deprecated Please import from `@backstage/backend-defaults/discovery` instead. */ export class HostDiscovery implements DiscoveryService { /** diff --git a/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts b/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts index bfc5a6a489..b29a589438 100644 --- a/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts @@ -20,7 +20,10 @@ import { } from '@backstage/backend-plugin-api'; import { HostDiscovery } from './HostDiscovery'; -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/discovery` instead. + */ export const discoveryServiceFactory = createServiceFactory({ service: coreServices.discovery, deps: { diff --git a/packages/backend-app-api/src/services/implementations/identity/identityServiceFactory.ts b/packages/backend-app-api/src/services/implementations/identity/identityServiceFactory.ts index 58da1c37d5..c2f1a61007 100644 --- a/packages/backend-app-api/src/services/implementations/identity/identityServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/identity/identityServiceFactory.ts @@ -24,16 +24,22 @@ import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; * An identity client options object which allows extra configurations * * @public + * @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead */ export type IdentityFactoryOptions = { issuer?: string; - /** JWS "alg" (Algorithm) Header Parameter values. Defaults to an array containing just ES256. - * More info on supported algorithms: https://github.com/panva/jose */ + /** + * JWS "alg" (Algorithm) Header Parameter values. Defaults to an array containing just ES256. + * More info on supported algorithms: https://github.com/panva/jose + */ algorithms?: string[]; }; -/** @public */ +/** + * @public + * @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead + */ export const identityServiceFactory = createServiceFactory( (options?: IdentityFactoryOptions) => ({ service: coreServices.identity, diff --git a/packages/backend-app-api/src/services/implementations/index.ts b/packages/backend-app-api/src/services/implementations/index.ts index a1114ab3e3..e6656801a9 100644 --- a/packages/backend-app-api/src/services/implementations/index.ts +++ b/packages/backend-app-api/src/services/implementations/index.ts @@ -28,7 +28,8 @@ export * from './permissions'; export * from './rootHttpRouter'; export * from './rootLifecycle'; export * from './rootLogger'; -export * from './scheduler'; export * from './tokenManager'; export * from './urlReader'; export * from './userInfo'; + +export * from './deprecated'; diff --git a/packages/backend-app-api/src/services/implementations/lifecycle/lifecycleServiceFactory.ts b/packages/backend-app-api/src/services/implementations/lifecycle/lifecycleServiceFactory.ts index 2b68a81807..b3b0135a7c 100644 --- a/packages/backend-app-api/src/services/implementations/lifecycle/lifecycleServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/lifecycle/lifecycleServiceFactory.ts @@ -26,7 +26,10 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; -/** @internal */ +/** + * @internal + * @deprecated + */ export class BackendPluginLifecycleImpl implements LifecycleService { constructor( private readonly logger: LoggerService, @@ -85,7 +88,9 @@ export class BackendPluginLifecycleImpl implements LifecycleService { /** * Allows plugins to register shutdown hooks that are run when the process is about to exit. + * * @public + * @deprecated Please import from `@backstage/backend-defaults/lifecycle` instead. */ export const lifecycleServiceFactory = createServiceFactory({ service: coreServices.lifecycle, diff --git a/packages/backend-app-api/src/services/implementations/permissions/permissionsServiceFactory.ts b/packages/backend-app-api/src/services/implementations/permissions/permissionsServiceFactory.ts index 9824eb2145..c8fa0e7bbf 100644 --- a/packages/backend-app-api/src/services/implementations/permissions/permissionsServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/permissions/permissionsServiceFactory.ts @@ -20,7 +20,10 @@ import { } from '@backstage/backend-plugin-api'; import { ServerPermissionClient } from '@backstage/plugin-permission-node'; -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/permissions` instead. + */ export const permissionsServiceFactory = createServiceFactory({ service: coreServices.permissions, deps: { diff --git a/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.test.ts index 91cb9031ae..5992e38d50 100644 --- a/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.test.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; import { BackendLifecycleImpl } from './rootLifecycleServiceFactory'; +import { mockServices } from '@backstage/backend-test-utils'; describe('lifecycleService', () => { it('should execute registered shutdown hook', async () => { - const service = new BackendLifecycleImpl(getVoidLogger()); + const service = new BackendLifecycleImpl(mockServices.logger.mock()); const hook = jest.fn(); service.addShutdownHook(() => hook()); // should not execute the hook more than once. @@ -30,7 +30,7 @@ describe('lifecycleService', () => { }); it('should not throw errors', async () => { - const service = new BackendLifecycleImpl(getVoidLogger()); + const service = new BackendLifecycleImpl(mockServices.logger.mock()); service.addShutdownHook(() => { throw new Error('oh no'); }); @@ -38,7 +38,7 @@ describe('lifecycleService', () => { }); it('should not throw async errors', async () => { - const service = new BackendLifecycleImpl(getVoidLogger()); + const service = new BackendLifecycleImpl(mockServices.logger.mock()); service.addShutdownHook(async () => { throw new Error('oh no'); }); @@ -46,7 +46,7 @@ describe('lifecycleService', () => { }); it('should reject hooks after trigger', async () => { - const service = new BackendLifecycleImpl(getVoidLogger()); + const service = new BackendLifecycleImpl(mockServices.logger.mock()); await service.startup(); expect(() => { service.addStartupHook(() => {}); diff --git a/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.ts b/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.ts index 197f99b97a..bf5dc09b80 100644 --- a/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/rootLifecycle/rootLifecycleServiceFactory.ts @@ -25,7 +25,10 @@ import { LoggerService, } from '@backstage/backend-plugin-api'; -/** @internal */ +/** + * @internal + * @deprecated + */ export class BackendLifecycleImpl implements RootLifecycleService { constructor(private readonly logger: LoggerService) {} @@ -108,6 +111,7 @@ export class BackendLifecycleImpl implements RootLifecycleService { * Allows plugins to register shutdown hooks that are run when the process is about to exit. * * @public + * @deprecated Please import from `@backstage/backend-defaults/rootLifecycle` instead. */ export const rootLifecycleServiceFactory = createServiceFactory({ service: coreServices.rootLifecycle, diff --git a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.ts b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.ts index dc9b3a9864..b4370761d9 100644 --- a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.ts @@ -20,7 +20,10 @@ import { } from '@backstage/backend-plugin-api'; import { TaskScheduler } from '@backstage/backend-tasks'; -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/scheduler` instead. + */ export const schedulerServiceFactory = createServiceFactory({ service: coreServices.scheduler, deps: { diff --git a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts index cad1b06035..e7c4ce7af0 100644 --- a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts @@ -20,7 +20,10 @@ import { } from '@backstage/backend-plugin-api'; import { ServerTokenManager } from '@backstage/backend-common'; -/** @public */ +/** + * @public + * @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead + */ export const tokenManagerServiceFactory = createServiceFactory({ service: coreServices.tokenManager, deps: { diff --git a/packages/backend-app-api/src/services/implementations/urlReader/urlReaderServiceFactory.ts b/packages/backend-app-api/src/services/implementations/urlReader/urlReaderServiceFactory.ts index 7f404a24b1..44caf25ad6 100644 --- a/packages/backend-app-api/src/services/implementations/urlReader/urlReaderServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/urlReader/urlReaderServiceFactory.ts @@ -20,7 +20,10 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; -/** @public */ +/** + * @public + * @deprecated Please import from `@backstage/backend-defaults/urlReader` instead. + */ export const urlReaderServiceFactory = createServiceFactory({ service: coreServices.urlReader, deps: { diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index fe949c2e33..ddad94de14 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -20,9 +20,9 @@ import { coreServices, ServiceRef, ServiceFactory, + LifecycleService, + RootLifecycleService, } from '@backstage/backend-plugin-api'; -import { BackendLifecycleImpl } from '../services/implementations/rootLifecycle/rootLifecycleServiceFactory'; -import { BackendPluginLifecycleImpl } from '../services/implementations/lifecycle/lifecycleServiceFactory'; import { ServiceOrExtensionPoint } from './types'; // Direct internal import to avoid duplication // eslint-disable-next-line @backstage/no-forbidden-package-imports @@ -31,6 +31,7 @@ import { ForwardedError, ConflictError } from '@backstage/errors'; import { featureDiscoveryServiceRef } from '@backstage/backend-plugin-api/alpha'; import { DependencyGraph } from '../lib/DependencyGraph'; import { ServiceRegistry } from './ServiceRegistry'; +import { createInitializationLogger } from './createInitializationLogger'; export interface BackendRegisterInit { consumes: Set; @@ -226,6 +227,11 @@ export class BackendInitializer { const allPluginIds = [...pluginInits.keys()]; + const initLogger = createInitializationLogger( + allPluginIds, + await this.#serviceRegistry.get(coreServices.rootLogger, 'root'), + ); + // All plugins are initialized in parallel await Promise.all( allPluginIds.map(async pluginId => { @@ -289,6 +295,8 @@ export class BackendInitializer { }); } + initLogger.onPluginStarted(pluginId); + // Once the plugin and all modules have been initialized, we can signal that the plugin has stared up successfully const lifecycleService = await this.#getPluginLifecycleImpl(pluginId); await lifecycleService.startup(); @@ -299,6 +307,8 @@ export class BackendInitializer { const lifecycleService = await this.#getRootLifecycleImpl(); await lifecycleService.startup(); + initLogger.onAllStarted(); + // Once the backend is started, any uncaught errors or unhandled rejections are caught // and logged, in order to avoid crashing the entire backend on local failures. if (process.env.NODE_ENV !== 'test') { @@ -335,27 +345,42 @@ export class BackendInitializer { } // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this - async #getRootLifecycleImpl(): Promise { + async #getRootLifecycleImpl(): Promise< + RootLifecycleService & { + startup(): Promise; + shutdown(): Promise; + } + > { const lifecycleService = await this.#serviceRegistry.get( coreServices.rootLifecycle, 'root', ); - if (lifecycleService instanceof BackendLifecycleImpl) { - return lifecycleService; + + const service = lifecycleService as any; + if ( + service && + typeof service.startup === 'function' && + typeof service.shutdown === 'function' + ) { + return service; } + throw new Error('Unexpected root lifecycle service implementation'); } async #getPluginLifecycleImpl( pluginId: string, - ): Promise { + ): Promise }> { const lifecycleService = await this.#serviceRegistry.get( coreServices.lifecycle, pluginId, ); - if (lifecycleService instanceof BackendPluginLifecycleImpl) { - return lifecycleService; + + const service = lifecycleService as any; + if (service && typeof service.startup === 'function') { + return service; } + throw new Error('Unexpected plugin lifecycle service implementation'); } } diff --git a/packages/backend-app-api/src/wiring/createInitializationLogger.ts b/packages/backend-app-api/src/wiring/createInitializationLogger.ts new file mode 100644 index 0000000000..566b5507ec --- /dev/null +++ b/packages/backend-app-api/src/wiring/createInitializationLogger.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RootLoggerService } from '@backstage/backend-plugin-api'; + +const LOGGER_INTERVAL_MAX = 60_000; + +function joinIds(ids: Iterable): string { + return [...ids].map(id => `'${id}'`).join(', '); +} + +export function createInitializationLogger( + pluginIds: string[], + rootLogger?: RootLoggerService, +): { + onPluginStarted(pluginId: string): void; + onAllStarted(): void; +} { + const logger = rootLogger?.child({ type: 'initialization' }); + const starting = new Set(pluginIds); + const started = new Set(); + + logger?.info(`Plugin initialization started: ${joinIds(pluginIds)}`); + + const getInitStatus = () => { + let status = ''; + if (started.size > 0) { + status = `, newly initialized: ${joinIds(started)}`; + started.clear(); + } + if (starting.size > 0) { + status += `, still initializing: ${joinIds(starting)}`; + } + return status; + }; + + // Periodically log the initialization status with a fibonacci backoff + let interval = 1000; + let prevInterval = 0; + let timeout: NodeJS.Timeout | undefined; + const onTimeout = () => { + logger?.info(`Plugin initialization in progress${getInitStatus()}`); + + const nextInterval = Math.min(interval + prevInterval, LOGGER_INTERVAL_MAX); + prevInterval = interval; + interval = nextInterval; + + timeout = setTimeout(onTimeout, nextInterval); + }; + timeout = setTimeout(onTimeout, interval); + + return { + onPluginStarted(pluginId: string) { + starting.delete(pluginId); + started.add(pluginId); + }, + onAllStarted() { + logger?.info(`Plugin initialization complete${getInitStatus()}`); + + if (timeout) { + clearTimeout(timeout); + timeout = undefined; + } + }, + }; +} diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index fdeaf6d137..62a9108d8a 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,89 @@ # @backstage/backend-common +## 0.23.0-next.1 + +### Minor Changes + +- 02103be: Deprecated and moved over core services to `@backstage/backend-defaults` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + +## 0.22.1-next.0 + +### Patch Changes + +- c6c0919: Updated configuration schema to include the `useRedisSets` cache config option. +- 1779188: In preparation to the new backend system stable release, the `isDatabaseConflictError` helper have been moved to the `@backstage/backend-plugin-api` package and deprecated from `@backstage/backend-common`. +- 8869b8e: We are deprecating the legacy `createServiceBuilder` factory, so if you are still using it, please checkout the migration guide and [migrate](https://backstage.io/docs/backend-system/building-plugins-and-modules/migrating) your plugin to use the new backend system. +- 3bd04bb: We are deprecating the legacy router handlers and contexts in preparation for the new backend system stable release. +- 6a576dc: Deprecate legacy service logger helpers and stop using `getVoidLogger` in tests. +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.11.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## 0.22.0 + +### Minor Changes + +- ed83f85: Internal refactor of the database code. + + **BREAKING**: The helper functions `createDatabaseClient` and `ensureDatabaseExists` have been removed from the public interface, since they have no usage within the repository and never were suitable for calling from the outside. Please consider using `coreServices.database` or `DatabaseManager` directly wherever possible instead. + +### Patch Changes + +- 2cc750d: Added `HarnessURLReader` with `readUrl` support. +- 57f692e: Preparing for a stable new backend system release, we are deprecating utilities in the `backend-common` that are not used by the core framework, such as the isomorphic `Git` class. As we will no longer support the isomorphic `Git` utility in the framework packages, we recommend plugins that start maintaining their own implementation of this class. +- 0ec0796: Plugins created through the `legacyPlugin` helper are now able to authenticate requests from plugins that are fully implemented using the new backend system. This fixes the `Key for the ES256 algorithm must be one of type KeyObject or CryptoKey. Received an instance of Uint8Array` error. +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- ccc8851: Added config prop `ensureSchemaExists` to support postgres instances where user can create schemas but not databases. +- f66bbb4: Only create a single actual connection to memcache/redis, even in cases where many `CacheService` instances are made +- ba0b8b4: Added option to `ServerTokenManager.fromConfig` that allows it to be instantiated in production without any configured keys. +- Updated dependencies + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/integration@1.11.0 + +## 0.22.0-next.2 + +### Patch Changes + +- 2cc750d: Added `HarnessURLReader` with `readUrl` support. +- ccc8851: Added config prop `ensureSchemaExists` to support postgres instances where user can create schemas but not databases. +- Updated dependencies + - @backstage/integration@1.11.0-next.0 + +## 0.22.0-next.1 + +### Minor Changes + +- ed83f85: Internal refactor of the database code. + + **BREAKING**: The helper functions `createDatabaseClient` and `ensureDatabaseExists` have been removed from the public interface, since they have no usage within the repository and never were suitable for calling from the outside. Please consider using `coreServices.database` or `DatabaseManager` directly wherever possible instead. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + ## 0.21.8-next.0 ### Patch Changes diff --git a/packages/backend-common/api-report-alpha.md b/packages/backend-common/api-report-alpha.md index 9d60b68b6b..046e8264fb 100644 --- a/packages/backend-common/api-report-alpha.md +++ b/packages/backend-common/api-report-alpha.md @@ -5,14 +5,14 @@ ```ts import { Duration } from 'luxon'; -// @alpha +// @alpha @deprecated export interface Context { readonly abortSignal: AbortSignal; readonly deadline: Date | undefined; value(key: string): T | undefined; } -// @alpha +// @alpha @deprecated export class Contexts { static root(): Context; static withAbort( diff --git a/packages/backend-common/api-report-testUtils.md b/packages/backend-common/api-report-testUtils.md index 9dbdade10e..d53748234e 100644 --- a/packages/backend-common/api-report-testUtils.md +++ b/packages/backend-common/api-report-testUtils.md @@ -3,24 +3,19 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -// @public -export function overridePackagePathResolution( - options: OverridePackagePathResolutionOptions, -): PackagePathResolutionOverride; +import { overridePackagePathResolution as overridePackagePathResolution_2 } from '@backstage/backend-plugin-api/testUtils'; +import { OverridePackagePathResolutionOptions as OverridePackagePathResolutionOptions_2 } from '@backstage/backend-plugin-api/testUtils'; +import { PackagePathResolutionOverride as PackagePathResolutionOverride_2 } from '@backstage/backend-plugin-api/testUtils'; -// @public (undocumented) -export interface OverridePackagePathResolutionOptions { - packageName: string; - path?: string; - paths?: { - [path in string]: string | (() => string); - }; -} +// @public @deprecated (undocumented) +export const overridePackagePathResolution: typeof overridePackagePathResolution_2; -// @public (undocumented) -export interface PackagePathResolutionOverride { - restore(): void; -} +// @public @deprecated (undocumented) +export type OverridePackagePathResolutionOptions = + OverridePackagePathResolutionOptions_2; + +// @public @deprecated (undocumented) +export type PackagePathResolutionOverride = PackagePathResolutionOverride_2; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index f9e0d76aab..758924b346 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -17,11 +17,12 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { BitbucketCloudIntegration } from '@backstage/integration'; import { BitbucketIntegration } from '@backstage/integration'; import { BitbucketServerIntegration } from '@backstage/integration'; -import { CacheService as CacheClient } from '@backstage/backend-plugin-api'; -import { CacheServiceOptions as CacheClientOptions } from '@backstage/backend-plugin-api'; -import { CacheServiceSetOptions as CacheClientSetOptions } from '@backstage/backend-plugin-api'; +import { CacheService } from '@backstage/backend-plugin-api'; +import { CacheServiceOptions } from '@backstage/backend-plugin-api'; +import type { CacheServiceSetOptions } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; import cors from 'cors'; +import { DiscoveryService } from '@backstage/backend-plugin-api'; import Docker from 'dockerode'; import { ErrorRequestHandler } from 'express'; import express from 'express'; @@ -30,12 +31,12 @@ import { GiteaIntegration } from '@backstage/integration'; import { GithubCredentialsProvider } from '@backstage/integration'; import { GithubIntegration } from '@backstage/integration'; import { GitLabIntegration } from '@backstage/integration'; +import { HarnessIntegration } from '@backstage/integration'; import { HostDiscovery as HostDiscovery_2 } from '@backstage/backend-app-api'; import { HttpAuthService } from '@backstage/backend-plugin-api'; import { IdentityService } from '@backstage/backend-plugin-api'; -import { isChildPath } from '@backstage/cli-common'; -import { Knex } from 'knex'; -import knexFactory from 'knex'; +import { isChildPath as isChildPath_2 } from '@backstage/backend-plugin-api'; +import { isDatabaseConflictError as isDatabaseConflictError_2 } from '@backstage/backend-plugin-api'; import { KubeConfig } from '@kubernetes/client-node'; import { LifecycleService } from '@backstage/backend-plugin-api'; import { LoadConfigOptionsRemote } from '@backstage/config-loader'; @@ -44,7 +45,6 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import { MergeResult } from 'isomorphic-git'; import { PermissionsService } from '@backstage/backend-plugin-api'; import { DatabaseService as PluginDatabaseManager } from '@backstage/backend-plugin-api'; -import { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api'; import { PluginMetadataService } from '@backstage/backend-plugin-api'; import { PushResult } from 'isomorphic-git'; import { Readable } from 'stream'; @@ -56,6 +56,8 @@ import { ReadTreeResponseFile } from '@backstage/backend-plugin-api'; import { ReadUrlOptions } from '@backstage/backend-plugin-api'; import { ReadUrlResponse } from '@backstage/backend-plugin-api'; import { RequestHandler } from 'express'; +import { resolvePackagePath as resolvePackagePath_2 } from '@backstage/backend-plugin-api'; +import { resolveSafeChildPath as resolveSafeChildPath_2 } from '@backstage/backend-plugin-api'; import { RootConfigService } from '@backstage/backend-plugin-api'; import { Router } from 'express'; import { SchedulerService } from '@backstage/backend-plugin-api'; @@ -72,7 +74,7 @@ import { V1PodTemplateSpec } from '@kubernetes/client-node'; import * as winston from 'winston'; import { Writable } from 'stream'; -// @public +// @public @deprecated export type AuthCallbackOptions = { onAuth: AuthCallback; logger?: LoggerService; @@ -191,18 +193,26 @@ export class BitbucketUrlReader implements UrlReader { toString(): string; } -export { CacheClient }; +// @public @deprecated (undocumented) +export type CacheClient = CacheService; -export { CacheClientOptions }; +// @public @deprecated (undocumented) +export type CacheClientOptions = CacheServiceOptions; -export { CacheClientSetOptions }; +// @public @deprecated (undocumented) +export type CacheClientSetOptions = CacheServiceSetOptions; // @public export class CacheManager { - forPlugin(pluginId: string): PluginCacheManager; + forPlugin(pluginId: string): { + getClient(options?: CacheServiceOptions): CacheService; + }; static fromConfig( config: Config, - options?: CacheManagerOptions, + options?: { + logger?: LoggerService; + onError?: (err: Error) => void; + }, ): CacheManager; } @@ -212,12 +222,12 @@ export type CacheManagerOptions = { onError?: (err: Error) => void; }; -// @public (undocumented) -export function cacheToPluginCacheManager( - cache: CacheClient, -): PluginCacheManager; - // @public +export function cacheToPluginCacheManager(cache: CacheService): { + getClient(options?: CacheServiceOptions): CacheService; +}; + +// @public @deprecated export const coloredFormat: winston.Logform.Format; // @public @@ -225,16 +235,6 @@ export interface ContainerRunner { runContainer(opts: RunContainerOptions): Promise; } -// @public -export function createDatabaseClient( - dbConfig: Config, - overrides?: Partial, - deps?: { - lifecycle: LifecycleService; - pluginMetadata: PluginMetadataService; - }, -): knexFactory.Knex; - // @public export function createLegacyAuthAdapters< TOptions extends { @@ -268,13 +268,13 @@ export function createLegacyAuthAdapters< : {}), >(options: TOptions): TAdapters; -// @public +// @public @deprecated export function createRootLogger( options?: winston.LoggerOptions, env?: NodeJS.ProcessEnv, ): winston.Logger; -// @public +// @public @deprecated export function createServiceBuilder(_module: NodeModule): ServiceBuilder; // @public @@ -312,19 +312,13 @@ export class DockerContainerRunner implements ContainerRunner { runContainer(options: RunContainerOptions): Promise; } -// @public +// @public @deprecated export function dropDatabase( dbConfig: Config, - ...databases: Array + ...databaseNames: string[] ): Promise; -// @public -export function ensureDatabaseExists( - dbConfig: Config, - ...databases: Array -): Promise; - -// @public +// @public @deprecated export function errorHandler( options?: ErrorHandlerOptions, ): ErrorRequestHandler; @@ -381,13 +375,13 @@ export class GerritUrlReader implements UrlReader { toString(): string; } -// @public +// @public @deprecated export function getRootLogger(): winston.Logger; -// @public +// @public @deprecated export function getVoidLogger(): winston.Logger; -// @public +// @public @deprecated export class Git { // (undocumented) add(options: { dir: string; filepath: string }): Promise; @@ -531,12 +525,30 @@ export class GitlabUrlReader implements UrlReader { } // @public +export class HarnessUrlReader implements UrlReader { + constructor(integration: HarnessIntegration); + // (undocumented) + static factory: ReaderFactory; + // (undocumented) + read(url: string): Promise; + // (undocumented) + readTree(): Promise; + // (undocumented) + readUrl(url: string, options?: ReadUrlOptions): Promise; + // (undocumented) + search(): Promise; + // (undocumented) + toString(): string; +} + +// @public @deprecated export const HostDiscovery: typeof HostDiscovery_2; -export { isChildPath }; +// @public @deprecated (undocumented) +export const isChildPath: typeof isChildPath_2; -// @public -export function isDatabaseConflictError(e: unknown): boolean; +// @public @deprecated (undocumented) +export const isDatabaseConflictError: typeof isDatabaseConflictError_2; // @public export class KubernetesContainerRunner implements ContainerRunner { @@ -571,10 +583,10 @@ export const legacyPlugin: ( default: LegacyCreateRouter< TransformedEnv< { - cache: CacheClient; + cache: CacheService; config: RootConfigService; database: PluginDatabaseManager; - discovery: PluginEndpointDiscovery; + discovery: DiscoveryService; logger: LoggerService; permissions: PermissionsService; scheduler: SchedulerService; @@ -584,7 +596,9 @@ export const legacyPlugin: ( }, { logger: (log: LoggerService) => Logger; - cache: (cache: CacheClient) => PluginCacheManager; + cache: (cache: CacheService) => { + getClient(options?: CacheServiceOptions | undefined): CacheService; + }; } > >; @@ -596,7 +610,7 @@ export type LegacyRootDatabaseService = { forPlugin(pluginId: string): PluginDatabaseManager; }; -// @public +// @public @deprecated export function loadBackendConfig(options: { logger: LoggerService; remote?: LoadConfigOptionsRemote; @@ -635,12 +649,13 @@ export function notFoundHandler(): RequestHandler; // @public (undocumented) export interface PluginCacheManager { // (undocumented) - getClient(options?: CacheClientOptions): CacheClient; + getClient(options?: CacheServiceOptions): CacheService; } export { PluginDatabaseManager }; -export { PluginEndpointDiscovery }; +// @public @deprecated (undocumented) +export type PluginEndpointDiscovery = DiscoveryService; // @public export interface PullOptions { @@ -730,7 +745,7 @@ export function redactWinstonLogLine( info: winston.Logform.TransformableInfo, ): winston.Logform.TransformableInfo; -// @public +// @public @deprecated export function requestLoggingHandler(logger?: LoggerService): RequestHandler; // @public @@ -738,11 +753,11 @@ export type RequestLoggingHandlerFactory = ( logger?: LoggerService, ) => RequestHandler; -// @public -export function resolvePackagePath(name: string, ...paths: string[]): string; +// @public @deprecated (undocumented) +export const resolvePackagePath: typeof resolvePackagePath_2; -// @public -export function resolveSafeChildPath(base: string, path: string): string; +// @public @deprecated (undocumented) +export const resolveSafeChildPath: typeof resolveSafeChildPath_2; // @public export type RunContainerOptions = { @@ -812,13 +827,13 @@ export type ServiceBuilder = { start(): Promise; }; -// @public +// @public @deprecated export function setRootLogger(newLogger: winston.Logger): void; // @public @deprecated export const SingleHostDiscovery: typeof HostDiscovery_2; -// @public +// @public @deprecated export type StaticAuthOptions = { username?: string; password?: string; diff --git a/packages/backend-common/config.d.ts b/packages/backend-common/config.d.ts index 700d9a6c6c..ed253dd54d 100644 --- a/packages/backend-common/config.d.ts +++ b/packages/backend-common/config.d.ts @@ -111,6 +111,13 @@ export interface Config { * Defaults to true if unspecified. */ ensureExists?: boolean; + /** + * Whether to ensure the given database schema exists by creating it if it does not. + * Defaults to false if unspecified. + * + * NOTE: Currently only supported by the `pg` client when pluginDivisionMode: schema + */ + ensureSchemaExists?: boolean; /** * How plugins databases are managed/divided in the provided database instance. * @@ -147,6 +154,13 @@ export interface Config { * Defaults to base config if unspecified. */ ensureExists?: boolean; + /** + * Whether to ensure the given database schema exists by creating it if it does not. + * Defaults to false if unspecified. + * + * NOTE: Currently only supported by the `pg` client when pluginDivisionMode: schema + */ + ensureSchemaExists?: boolean; /** * Arbitrary config object to pass to knex when initializing * (https://knexjs.org/#Installation-client). Most notable is the @@ -177,6 +191,11 @@ export interface Config { connection: string; /** An optional default TTL (in milliseconds). */ defaultTtl?: number; + /** + * Whether or not [useRedisSets](https://github.com/jaredwray/keyv/tree/main/packages/redis#useredissets) should be configured to this redis cache. + * Defaults to true if unspecified. + */ + useRedisSets?: boolean; } | { store: 'memcache'; diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 0a08c58e54..6a72699739 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-common", - "version": "0.21.8-next.0", + "version": "0.23.0-next.1", "description": "Common functionality library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend-common/src/cache/CacheManager.test.ts b/packages/backend-common/src/cache/CacheManager.test.ts deleted file mode 100644 index 4b7bb05efd..0000000000 --- a/packages/backend-common/src/cache/CacheManager.test.ts +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ConfigReader } from '@backstage/config'; -import Keyv from 'keyv'; -import KeyvMemcache from '@keyv/memcache'; -import KeyvRedis from '@keyv/redis'; -import { DefaultCacheClient } from './CacheClient'; -import { CacheManager } from './CacheManager'; - -jest.createMockFromModule('keyv'); -jest.mock('keyv'); -jest.createMockFromModule('@keyv/memcache'); -jest.mock('@keyv/memcache'); -jest.createMockFromModule('@keyv/redis'); -jest.mock('@keyv/redis'); -jest.mock('./CacheClient', () => { - return { - DefaultCacheClient: jest.fn(), - }; -}); - -const globalDefaultTtl = 1234; -describe('CacheManager', () => { - const defaultConfigOptions = { - backend: { - cache: { - store: 'memory', - defaultTtl: globalDefaultTtl, - }, - }, - }; - const defaultConfig = () => new ConfigReader(defaultConfigOptions); - - afterEach(() => jest.resetAllMocks()); - - describe('CacheManager.fromConfig', () => { - it('accesses the backend.cache key', () => { - const getOptionalString = jest.fn(); - const getOptionalBoolean = jest.fn(); - const getOptionalNumber = jest.fn(); - const config = defaultConfig(); - config.getOptionalString = getOptionalString; - config.getOptionalBoolean = getOptionalBoolean; - config.getOptionalNumber = getOptionalNumber; - - CacheManager.fromConfig(config); - - expect(getOptionalString.mock.calls[0][0]).toEqual('backend.cache.store'); - expect(getOptionalString.mock.calls[1][0]).toEqual( - 'backend.cache.connection', - ); - expect(getOptionalBoolean.mock.calls[0][0]).toEqual( - 'backend.cache.useRedisSets', - ); - expect(getOptionalNumber.mock.calls[0][0]).toEqual( - 'backend.cache.defaultTtl', - ); - }); - - it('does not require the backend.cache key', () => { - const config = new ConfigReader({ backend: {} }); - expect(() => { - CacheManager.fromConfig(config); - }).not.toThrow(); - }); - - it('throws on unknown cache store', () => { - const config = new ConfigReader({ - backend: { cache: { store: 'notreal' } }, - }); - expect(() => { - CacheManager.fromConfig(config); - }).toThrow(); - }); - }); - - describe('CacheManager.forPlugin', () => { - const manager = CacheManager.fromConfig(defaultConfig()); - - it('connects to a cache store scoped to the plugin', async () => { - const pluginId = 'test1'; - manager.forPlugin(pluginId).getClient(); - - const client = DefaultCacheClient as jest.Mock; - expect(client).toHaveBeenCalledTimes(1); - }); - - it('attaches error handler to client', () => { - const pluginId = 'error-test'; - manager.forPlugin(pluginId).getClient(); - - const client = DefaultCacheClient as jest.Mock; - const mockCalls = client.mock.calls.splice(-1); - const realClient = mockCalls[0][0] as Keyv; - expect(realClient.on).toHaveBeenCalledWith('error', expect.any(Function)); - }); - - it('provides different plugins different cache clients', async () => { - const plugin1Id = 'test1'; - const plugin2Id = 'test2'; - const expectedTtl = 3600; - manager.forPlugin(plugin1Id).getClient({ defaultTtl: expectedTtl }); - manager.forPlugin(plugin2Id).getClient({ defaultTtl: expectedTtl }); - - const client = DefaultCacheClient as jest.Mock; - const cache = Keyv as unknown as jest.Mock; - expect(cache).toHaveBeenCalledTimes(2); - expect(client).toHaveBeenCalledTimes(2); - - const plugin1CallArgs = cache.mock.calls[0]; - const plugin2CallArgs = cache.mock.calls[1]; - expect(plugin1CallArgs[0].namespace).not.toEqual( - plugin2CallArgs[0].namespace, - ); - }); - }); - - describe('CacheManager.forPlugin stores', () => { - it('returns memory client when no cache is configured', () => { - const manager = CacheManager.fromConfig( - new ConfigReader({ backend: {} }), - ); - const expectedTtl = 3600; - const expectedNamespace = 'test-plugin'; - manager - .forPlugin(expectedNamespace) - .getClient({ defaultTtl: expectedTtl }); - - const cache = Keyv as unknown as jest.Mock; - const mockCalls = cache.mock.calls.splice(-1); - const callArgs = mockCalls[0]; - expect(callArgs[0]).toMatchObject({ - ttl: expectedTtl, - namespace: expectedNamespace, - }); - }); - - it('returns memory client when explicitly configured', () => { - const manager = CacheManager.fromConfig(defaultConfig()); - const expectedTtl = 3600; - const expectedNamespace = 'test-plugin'; - manager - .forPlugin(expectedNamespace) - .getClient({ defaultTtl: expectedTtl }); - - const cache = Keyv as unknown as jest.Mock; - const mockCalls = cache.mock.calls.splice(-1); - const callArgs = mockCalls[0]; - expect(callArgs[0]).toMatchObject({ - ttl: expectedTtl, - namespace: expectedNamespace, - }); - }); - - it('returns memory client with a global defaultTtl when explicitly configured', () => { - const manager = CacheManager.fromConfig(defaultConfig()); - const expectedNamespace = 'test-plugin'; - manager.forPlugin(expectedNamespace).getClient(); - - const cache = Keyv as unknown as jest.Mock; - const mockCalls = cache.mock.calls.splice(-1); - const callArgs = mockCalls[0]; - expect(callArgs[0]).toMatchObject({ - ttl: globalDefaultTtl, - namespace: expectedNamespace, - }); - }); - - it('shares memory across multiple instances of the memory client', () => { - const manager = CacheManager.fromConfig(defaultConfig()); - const plugin = 'test-plugin'; - - // Instantiate two in-memory clients. - manager.forPlugin(plugin).getClient({ defaultTtl: 10 }); - manager.forPlugin(plugin).getClient({ defaultTtl: 10 }); - - const cache = Keyv as unknown as jest.Mock; - const mockCall2 = cache.mock.calls.splice(-1)[0][0]; - const mockCall1 = cache.mock.calls.splice(-1)[0][0]; - - // Note: .toBe() checks referential identity of object instances. - expect(mockCall1.store).toBe(mockCall2.store); - }); - - it('returns a memcache client when configured', () => { - const expectedHost = '127.0.0.1:11211'; - const manager = CacheManager.fromConfig( - new ConfigReader({ - backend: { - cache: { - store: 'memcache', - connection: expectedHost, - }, - }, - }), - ); - const expectedTtl = 3600; - manager.forPlugin('test').getClient({ defaultTtl: expectedTtl }); - - const cache = Keyv as unknown as jest.Mock; - const mockCacheCalls = cache.mock.calls.splice(-1); - expect(mockCacheCalls[0][0]).toMatchObject({ - ttl: expectedTtl, - }); - expect(mockCacheCalls[0][0].store).toBeInstanceOf(KeyvMemcache); - const memcache = KeyvMemcache as unknown as jest.Mock; - const mockMemcacheCalls = memcache.mock.calls.splice(-1); - expect(mockMemcacheCalls[0][0]).toEqual(expectedHost); - }); - - it('returns a memcache client with a global defaultTtl when configured', () => { - const expectedHost = '127.0.0.1:11211'; - const manager = CacheManager.fromConfig( - new ConfigReader({ - backend: { - cache: { - store: 'memcache', - connection: expectedHost, - defaultTtl: globalDefaultTtl, - }, - }, - }), - ); - manager.forPlugin('test').getClient(); - - const cache = Keyv as unknown as jest.Mock; - const mockCacheCalls = cache.mock.calls.splice(-1); - expect(mockCacheCalls[0][0]).toMatchObject({ - ttl: globalDefaultTtl, - }); - expect(mockCacheCalls[0][0].store).toBeInstanceOf(KeyvMemcache); - const memcache = KeyvMemcache as unknown as jest.Mock; - const mockMemcacheCalls = memcache.mock.calls.splice(-1); - expect(mockMemcacheCalls[0][0]).toEqual(expectedHost); - }); - - it('returns a Redis client when configured', () => { - const redisConnection = 'redis://127.0.0.1:6379'; - const manager = CacheManager.fromConfig( - new ConfigReader({ - backend: { - cache: { - store: 'redis', - connection: redisConnection, - }, - }, - }), - ); - const expectedTtl = 3600; - manager.forPlugin('test').getClient({ defaultTtl: expectedTtl }); - - const cache = Keyv as unknown as jest.Mock; - const mockCacheCalls = cache.mock.calls.splice(-1); - expect(mockCacheCalls[0][0]).toMatchObject({ - ttl: expectedTtl, - }); - expect(mockCacheCalls[0][0].store).toBeInstanceOf(KeyvRedis); - const redis = KeyvRedis as unknown as jest.Mock; - const mockRedisCalls = redis.mock.calls.splice(-1); - expect(mockRedisCalls[0][0]).toEqual(redisConnection); - }); - - it('returns a Redis client with a global defaultTtl when configured', () => { - const redisConnection = 'redis://127.0.0.1:6379'; - const manager = CacheManager.fromConfig( - new ConfigReader({ - backend: { - cache: { - store: 'redis', - connection: redisConnection, - defaultTtl: globalDefaultTtl, - }, - }, - }), - ); - manager.forPlugin('test').getClient(); - - const cache = Keyv as unknown as jest.Mock; - const mockCacheCalls = cache.mock.calls.splice(-1); - expect(mockCacheCalls[0][0]).toMatchObject({ - ttl: globalDefaultTtl, - }); - expect(mockCacheCalls[0][0].store).toBeInstanceOf(KeyvRedis); - const redis = KeyvRedis as unknown as jest.Mock; - const mockRedisCalls = redis.mock.calls.splice(-1); - expect(mockRedisCalls[0][0]).toEqual(redisConnection); - }); - - it('returns a Redis client when configured with useRedisSets flag', () => { - const redisConnection = 'redis://127.0.0.1:6379'; - const useRedisSets = false; - const manager = CacheManager.fromConfig( - new ConfigReader({ - backend: { - cache: { - store: 'redis', - connection: redisConnection, - useRedisSets: useRedisSets, - }, - }, - }), - ); - const expectedTtl = 3600; - manager.forPlugin('test').getClient({ defaultTtl: expectedTtl }); - - const cache = Keyv as unknown as jest.Mock; - const mockCacheCalls = cache.mock.calls.splice(-1); - expect(mockCacheCalls[0][0]).toMatchObject({ - ttl: expectedTtl, - useRedisSets: useRedisSets, - }); - expect(mockCacheCalls[0][0].store).toBeInstanceOf(KeyvRedis); - const redis = KeyvRedis as unknown as jest.Mock; - const mockRedisCalls = redis.mock.calls.splice(-1); - expect(mockRedisCalls[0][0]).toEqual(redisConnection); - }); - }); - - describe('connection errors', () => { - it('uses provided logger', () => { - // Set up and inject mock logger. - const mockLogger = { child: jest.fn(), error: jest.fn() }; - mockLogger.child.mockImplementation(() => mockLogger as any); - const manager = CacheManager.fromConfig(defaultConfig(), { - logger: mockLogger as any, - }); - - // Set up a cache client using the configured manager. - manager.forPlugin('error-logger-test').getClient(); - - // Retrieve the error handler attached to the cache client. - const client = DefaultCacheClient as jest.Mock; - const mockCalls = client.mock.calls.splice(-1); - const realClient = mockCalls[0][0] as Keyv; - const realOnError = realClient.on as jest.Mock; - const realHandler = realOnError.mock.calls.splice(-1)[0][1]; - - // Invoke the actual error handler. - const expectedError = new Error('some error'); - realHandler(expectedError); - expect(mockLogger.error).toHaveBeenCalledWith( - 'Failed to create cache client', - expectedError, - ); - }); - - it('calls provided handler', () => { - // Set up and inject mock logger. - const mockHandler = jest.fn(); - const manager = CacheManager.fromConfig(defaultConfig(), { - onError: mockHandler, - }); - - // Set up a cache client using the configured manager. - manager.forPlugin('error-handler-test').getClient(); - - // Retrieve the error handler attached to the cache client. - const client = DefaultCacheClient as jest.Mock; - const mockCalls = client.mock.calls.splice(-1); - const realClient = mockCalls[0][0] as Keyv; - const realOnError = realClient.on as jest.Mock; - const realHandler = realOnError.mock.calls.splice(-1)[0][1]; - - // Invoke the actual error handler. - const expectedError = new Error('some error'); - realHandler(expectedError); - expect(mockHandler).toHaveBeenCalledWith(expectedError); - }); - }); -}); diff --git a/packages/backend-common/src/cache/cacheToPluginCacheManager.ts b/packages/backend-common/src/cache/cacheToPluginCacheManager.ts new file mode 100644 index 0000000000..2654934804 --- /dev/null +++ b/packages/backend-common/src/cache/cacheToPluginCacheManager.ts @@ -0,0 +1,34 @@ +/* + * 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 { + CacheService, + CacheServiceOptions, +} from '@backstage/backend-plugin-api'; + +/** + * Compatibility wrapper for going from a new-backend cache service to the + * old-backend plugin cache manager. + * + * @public + */ +export function cacheToPluginCacheManager(cache: CacheService): { + getClient(options?: CacheServiceOptions): CacheService; +} { + return { + getClient: (opts: CacheServiceOptions) => cache.withOptions(opts), + }; +} diff --git a/packages/backend-common/src/cache/index.ts b/packages/backend-common/src/cache/index.ts index 0187aa45d5..9d05745ebd 100644 --- a/packages/backend-common/src/cache/index.ts +++ b/packages/backend-common/src/cache/index.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -export { CacheManager, cacheToPluginCacheManager } from './CacheManager'; -export type { - CacheClient, - CacheClientSetOptions, - PluginCacheManager, - CacheManagerOptions, - CacheClientOptions, -} from './types'; +export { cacheToPluginCacheManager } from './cacheToPluginCacheManager'; +export * from './reexport'; +export * from './types'; diff --git a/packages/backend-common/src/cache/reexport.ts b/packages/backend-common/src/cache/reexport.ts new file mode 100644 index 0000000000..9f6106de60 --- /dev/null +++ b/packages/backend-common/src/cache/reexport.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * NOTE(freben): This is a temporary hack. We use cross-package imports so that + * we do not have to maintain double implementations for the time being, until + * backend-common is properly removed. + */ + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +export { CacheManager } from '../../../backend-defaults/src/entrypoints/cache/CacheManager'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +export { + type PluginCacheManager, + type CacheManagerOptions, +} from '../../../backend-defaults/src/entrypoints/cache/types'; diff --git a/packages/backend-common/src/cache/types.ts b/packages/backend-common/src/cache/types.ts index 93fa0ac77c..83b6916843 100644 --- a/packages/backend-common/src/cache/types.ts +++ b/packages/backend-common/src/cache/types.ts @@ -14,39 +14,26 @@ * limitations under the License. */ -import { LoggerService } from '@backstage/backend-plugin-api'; -import { +import type { CacheService, + CacheServiceSetOptions, CacheServiceOptions, } from '@backstage/backend-plugin-api'; -export type { - CacheService as CacheClient, - CacheServiceSetOptions as CacheClientSetOptions, - CacheServiceOptions as CacheClientOptions, -} from '@backstage/backend-plugin-api'; - /** - * Options given when constructing a {@link CacheManager}. - * * @public + * @deprecated Use `CacheService` from the `@backstage/backend-plugin-api` package instead */ -export type CacheManagerOptions = { - /** - * An optional logger for use by the PluginCacheManager. - */ - logger?: LoggerService; - - /** - * An optional handler for connection errors emitted from the underlying data - * store. - */ - onError?: (err: Error) => void; -}; +export type CacheClient = CacheService; /** * @public + * @deprecated Use `CacheServiceSetOptions` from the `@backstage/backend-plugin-api` package instead */ -export interface PluginCacheManager { - getClient(options?: CacheServiceOptions): CacheService; -} +export type CacheClientSetOptions = CacheServiceSetOptions; + +/** + * @public + * @deprecated Use `CacheServiceOptions` from the `@backstage/backend-plugin-api` package instead + */ +export type CacheClientOptions = CacheServiceOptions; diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts index b452d8db70..1dfa9643e2 100644 --- a/packages/backend-common/src/config.ts +++ b/packages/backend-common/src/config.ts @@ -29,6 +29,7 @@ import { setRootLoggerRedactionList } from './logging/createRootLogger'; * This function should only be called once, during the initialization of the backend. * * @public + * @deprecated Use {@link @backstage/backend-app-api#loadBackendConfig} instead. */ export async function loadBackendConfig(options: { logger: LoggerService; diff --git a/packages/backend-common/src/context/Contexts.ts b/packages/backend-common/src/context/Contexts.ts index 4eeb56b029..026e3ce4e0 100644 --- a/packages/backend-common/src/context/Contexts.ts +++ b/packages/backend-common/src/context/Contexts.ts @@ -24,6 +24,7 @@ import { ValueContext } from './ValueContext'; * Common context decorators. * * @alpha + * @deprecated This class is not used in the new Backend system, so it is going to be removed in a near future. */ export class Contexts { /** diff --git a/packages/backend-common/src/context/types.ts b/packages/backend-common/src/context/types.ts index 3b53225163..d980f54e43 100644 --- a/packages/backend-common/src/context/types.ts +++ b/packages/backend-common/src/context/types.ts @@ -19,6 +19,7 @@ * to pass along scoped information and abort signals. * * @alpha + * @deprecated This type is not used in the new Backend system, so it is going to be removed in a near future. */ export interface Context { /** diff --git a/packages/backend-common/src/database/DatabaseManager.test.ts b/packages/backend-common/src/database/DatabaseManager.test.ts deleted file mode 100644 index bf4af17d05..0000000000 --- a/packages/backend-common/src/database/DatabaseManager.test.ts +++ /dev/null @@ -1,851 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ConfigReader } from '@backstage/config'; -import { omit } from 'lodash'; -import path from 'path'; -import { - createDatabaseClient, - ensureDatabaseExists, - ensureSchemaExists, -} from './connection'; -import { DatabaseManager } from './DatabaseManager'; - -jest.mock('./connection', () => ({ - ...jest.requireActual('./connection'), - createDatabaseClient: jest.fn(), - ensureDatabaseExists: jest.fn(), - ensureSchemaExists: jest.fn(), -})); - -describe('DatabaseManager', () => { - // This is similar to the ts-jest `mocked` helper. - const mocked = (f: Function) => f as jest.Mock; - - afterEach(() => jest.resetAllMocks()); - - describe('DatabaseManager.fromConfig', () => { - const backendConfig = { - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }; - - it('accesses the backend.database key', () => { - const config = new ConfigReader(backendConfig); - const getConfigSpy = jest.spyOn(config, 'getConfig'); - DatabaseManager.fromConfig(config); - - expect(getConfigSpy).toHaveBeenCalledWith('backend.database'); - }); - - it('handles default options', () => { - const config = new ConfigReader(backendConfig); - const database = DatabaseManager.fromConfig(config); - const client = database.forPlugin('test'); - - expect(client.migrations?.skip).toBe(false); - }); - - it('handles migrations options', () => { - const config = new ConfigReader(backendConfig); - const database = DatabaseManager.fromConfig(config, { - migrations: { skip: true }, - }); - const client = database.forPlugin('test'); - - expect(client.migrations?.skip).toBe(true); - }); - }); - - describe('DatabaseManager.forPlugin', () => { - const config = { - backend: { - database: { - client: 'pg', - prefix: 'test_prefix_', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - plugin: { - testdbname: { - connection: { - database: 'database_name_overridden', - }, - }, - differentclient: { - client: 'better-sqlite3', - connection: { - filename: 'plugin_with_different_client', - }, - }, - differentclientconnstring: { - client: 'better-sqlite3', - connection: ':memory:', - }, - stringoverride: { - connection: 'postgresql://testuser:testpass@acme:5432/userdbname', - }, - }, - }, - }, - }; - let manager: DatabaseManager; - - beforeEach(() => { - manager = DatabaseManager.fromConfig(new ConfigReader(config)); - }); - - it('connects to a plugin database using default config', async () => { - const pluginId = 'pluginwithoutconfig'; - - await manager.forPlugin(pluginId).getClient(); - expect(mocked(createDatabaseClient)).toHaveBeenCalledTimes(1); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - // default config should be passed through to underlying connector - expect(baseConfig.get()).toMatchObject({ - client: 'pg', - connection: omit(config.backend.database.connection, ['database']), - }); - - // override using database name generated from pluginId and prefix - expect(overrides).toMatchObject({ - connection: { - database: `${config.backend.database.prefix}${pluginId}`, - }, - }); - }); - - it('provides a plugin db which uses components from top level connection string', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: 'postgresql://foo:bar@acme:5432/foodb', - }, - }, - }), - ); - - await testManager.forPlugin('pluginwithoutconfig').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - // parsed connection string **without** db name should be passed through - expect(baseConfig.get()).toMatchObject({ - connection: { - host: 'acme', - user: 'foo', - password: 'bar', - port: '5432', - application_name: 'backstage_plugin_pluginwithoutconfig', - }, - }); - - // we expect a pg database name override with ${prefix} followed by pluginId - expect(overrides).toHaveProperty( - 'connection.database', - expect.stringContaining('pluginwithoutconfig'), - ); - }); - - it('provides an inmemory sqlite database if top level is also inmemory and plugin config is not present', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'better-sqlite3', - connection: ':memory:', - }, - }, - }), - ); - - await testManager.forPlugin('pluginwithoutconfig').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_, overrides] = mockCalls[0]; - - expect(overrides).toHaveProperty( - 'connection.filename', - expect.stringContaining(':memory:'), - ); - }); - - it('throws if top level sqlite filename is provided', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'better-sqlite3', - connection: 'some-file-path', - }, - }, - }), - ); - - await expect( - testManager.forPlugin('pluginwithoutconfig').getClient(), - ).rejects.toBeInstanceOf(Error); - }); - - it('creates plugin-specific sqlite files when plugin config is not present', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'better-sqlite3', - connection: { - directory: 'sqlite-files', - }, - }, - }, - }), - ); - - await testManager.forPlugin('pluginwithoutconfig').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_, overrides] = mockCalls[0]; - - expect(overrides).toHaveProperty( - 'connection.filename', - path.join('sqlite-files', 'pluginwithoutconfig.sqlite'), - ); - }); - - it('uses sqlite directory from top level config and filename from plugin config', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'better-sqlite3', - connection: { - directory: 'sqlite-files', - }, - plugin: { - test: { - connection: { - filename: 'other.sqlite', - }, - }, - }, - }, - }, - }), - ); - - await testManager.forPlugin('test').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_, overrides] = mockCalls[0]; - - expect(overrides).toHaveProperty( - 'connection.filename', - path.join('sqlite-files', 'other.sqlite'), - ); - }); - - it('uses sqlite directory and filename from plugin config', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'better-sqlite3', - connection: { - directory: 'sqlite-files', - }, - plugin: { - test: { - connection: { - directory: 'custom-sqlite-files', - filename: 'other.sqlite', - }, - }, - }, - }, - }, - }), - ); - - await testManager.forPlugin('test').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_, overrides] = mockCalls[0]; - - expect(overrides).toHaveProperty( - 'connection.filename', - path.join('custom-sqlite-files', 'other.sqlite'), - ); - }); - - it('connects to a plugin database using a specific database name', async () => { - // testdbname.connection.database is set in config - await manager.forPlugin('testdbname').getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_baseConfig, overrides] = mockCalls[0]; - - // simple case where only database name is overridden - expect(overrides).toMatchObject({ - connection: { - database: 'database_name_overridden', - }, - }); - }); - - it('ensure plugin specific database is created', async () => { - const pluginId = 'testdbname'; - // testdbname.connection.database is set in config - await manager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(ensureDatabaseExists).mock.calls.splice(-1); - const [_, dbname] = mockCalls[0]; - - expect(dbname).toEqual( - config.backend.database.plugin[pluginId].connection.database, - ); - }); - - it('provides different plugins with their own databases', async () => { - await manager.forPlugin('plugin1').getClient(); - await manager.forPlugin('plugin2').getClient(); - - expect(mocked(createDatabaseClient)).toHaveBeenCalledTimes(2); - - const mockCalls = mocked(createDatabaseClient).mock.calls; - const [plugin1CallArgs, plugin2CallArgs] = mockCalls; - - // database name overrides should be different - expect(plugin1CallArgs[1].connection.database).not.toEqual( - plugin2CallArgs[1].connection.database, - ); - }); - - it('returns the same client for the same pluginId', async () => { - const [client1, client2] = await Promise.all([ - manager.forPlugin('plugin1').getClient(), - manager.forPlugin('plugin1').getClient(), - ]); - expect(mocked(createDatabaseClient)).toHaveBeenCalledTimes(1); - - expect(client1).toBe(client2); - }); - - it('uses plugin connection as base if default client is different from plugin client', async () => { - const pluginId = 'differentclient'; - await manager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, _overrides] = mockCalls[0]; - - // plugin connection should be used as base config, client is different - expect(baseConfig.get()).toMatchObject({ - client: 'better-sqlite3', - connection: config.backend.database.plugin[pluginId].connection, - }); - }); - - it('provides database client specific base and override when client set under plugin', async () => { - const pluginId = 'differentclient'; - await manager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - // plugin client should be better-sqlite3 - expect(baseConfig.get().client).toEqual('better-sqlite3'); - - // SQLite uses 'filename' instead of 'database' - expect(overrides).toHaveProperty( - 'connection.filename', - 'plugin_with_different_client', - ); - }); - - it('provides database client specific base from plugin connection string when client set under plugin', async () => { - const pluginId = 'differentclientconnstring'; - await manager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - expect(baseConfig.get().client).toEqual('better-sqlite3'); - - expect(overrides).toHaveProperty('connection.filename', ':memory:'); - }); - - it('generates a database name override when prefix is not explicitly set', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }), - ); - - await testManager.forPlugin('testplugin').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_baseConfig, overrides] = mockCalls[0]; - - expect(overrides).toHaveProperty( - 'connection.database', - expect.stringContaining('backstage_plugin_'), - ); - }); - - it('generates a database name override when prefix is not explicitly set for mysql', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'mysql', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }), - ); - - await testManager.forPlugin('testplugin').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_baseConfig, overrides] = mockCalls[0]; - - expect(overrides).toHaveProperty( - 'connection.database', - expect.stringContaining('backstage_plugin_'), - ); - }); - - it('uses values from plugin connection string if top level client should be used', async () => { - const pluginId = 'stringoverride'; - await manager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - // plugin client should be pg - expect(baseConfig.get().client).toEqual('pg'); - - expect(overrides).toHaveProperty( - 'connection.database', - expect.stringContaining('userdbname'), - ); - }); - - it('plugin sets schema override for pg client', async () => { - const overrideConfig = { - backend: { - database: { - client: 'pg', - pluginDivisionMode: 'schema', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }; - const testManager = DatabaseManager.fromConfig( - new ConfigReader(overrideConfig), - ); - const pluginId = 'schemaoverride'; - await testManager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - expect(baseConfig.get()).toMatchObject({ - client: 'pg', - connection: config.backend.database.connection, - }); - - expect(overrides).toMatchObject({ - searchPath: [pluginId], - }); - }); - - it('plugin does not provide schema override for non pg client', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'better-sqlite3', - pluginDivisionMode: 'schema', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }), - ); - const pluginId = 'any-plugin'; - await testManager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - expect(baseConfig.get()).toMatchObject({ - client: 'better-sqlite3', - connection: config.backend.database.connection, - }); - - expect(overrides).not.toHaveProperty('searchPath'); - }); - - it('plugin does not provide schema override if pluginDivisionMode is set to database', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - pluginDivisionMode: 'database', - connection: 'some-file-path', - }, - }, - }), - ); - - const pluginId = 'any-plugin'; - await testManager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_baseConfig, overrides] = mockCalls[0]; - - expect(overrides).not.toHaveProperty('searchPath'); - }); - - it('plugin does not provide schema override if pluginDivisionMode is not set', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }), - ); - - const pluginId = 'schemaoverride'; - await testManager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_baseConfig, overrides] = mockCalls[0]; - - expect(overrides).not.toHaveProperty('searchPath'); - }); - - it('pluginDivisionMode ensures that each plugin schema exists', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - pluginDivisionMode: 'schema', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }), - ); - const pluginId = 'testdbname'; - await testManager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(ensureSchemaExists).mock.calls; - const [_, schemaName] = mockCalls[0]; - - expect(schemaName).toEqual('testdbname'); - }); - - it('pluginDivisionMode allows connection overrides for plugins', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - pluginDivisionMode: 'schema', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - plugin: { - testdbname: { - connection: { - database: 'database_name_overridden', - host: 'newhost', - }, - }, - }, - }, - }, - }), - ); - const pluginId = 'testdbname'; - await testManager.forPlugin(pluginId).getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - - expect(baseConfig.get()).toMatchObject({ - client: 'pg', - connection: { - database: 'database_name_overridden', - host: 'newhost', - user: 'foo', - password: 'bar', - }, - }); - expect(overrides).toHaveProperty('searchPath', ['testdbname']); - expect(overrides).toHaveProperty( - 'connection.database', - 'database_name_overridden', - ); - }); - - it('ensureExists does not create database or schema when false', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - pluginDivisionMode: 'schema', - ensureExists: false, - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }, - }, - }), - ); - const pluginId = 'testdbname'; - await testManager.forPlugin(pluginId).getClient(); - - expect(mocked(ensureDatabaseExists)).toHaveBeenCalledTimes(0); - expect(mocked(ensureSchemaExists)).toHaveBeenCalledTimes(0); - }); - - it('fetches and merges additional knex config', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - database: 'foodb', - }, - knexConfig: { - something: false, - }, - plugin: { - testdbname: { - knexConfig: { - debug: true, - }, - }, - }, - }, - }, - }), - ); - await testManager.forPlugin('testdbname').getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig] = mockCalls[0]; - - expect(baseConfig.data).toEqual( - expect.objectContaining({ - debug: true, - something: false, - }), - ); - }); - - it('sets the owner config for plugin using default config', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - database: 'foodb', - }, - role: 'backstage', - plugin: { - testowner: {}, - }, - }, - }, - }), - ); - await testManager.forPlugin('testowner').getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig] = mockCalls[0]; - - expect(baseConfig.data.role).toEqual('backstage'); - }); - - it('sets the owner config for plugin using plugin config', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - database: 'foodb', - }, - role: 'backstage', - plugin: { - testowner: { - role: 'backstage-plugin', - }, - }, - }, - }, - }), - ); - await testManager.forPlugin('testowner').getClient(); - - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig] = mockCalls[0]; - - expect(baseConfig.data.role).toEqual('backstage-plugin'); - }); - - it('Defaults the application_name for postgres clients', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: {}, - }, - }, - }), - ); - - await testManager.forPlugin('testplugin').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, _] = mockCalls[0]; - expect(baseConfig.get()).toMatchObject({ - connection: { - application_name: 'backstage_plugin_testplugin', - }, - }); - }); - - it('Allows manually setting the application_name for postgres clients', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - application_name: 'backstage_custom_app_name', - }, - }, - }, - }), - ); - - await testManager.forPlugin('testplugin').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, overrides] = mockCalls[0]; - expect(baseConfig.get().connection.application_name).toBe( - 'backstage_custom_app_name', - ); - expect(overrides.connection.application_name).toBeUndefined(); - }); - - it('Allows manually setting the application_name for individual plugin client', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'pg', - connection: { - host: 'localhost', - user: 'foo', - password: 'bar', - database: 'foodb', - application_name: 'backstage_custom_app_name', - }, - plugin: { - overrideplugin: { - connection: { - application_name: 'custom_plugin', - }, - }, - }, - }, - }, - }), - ); - - await testManager.forPlugin('overrideplugin').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [baseConfig, _] = mockCalls[0]; - expect(baseConfig.get().connection.application_name).toBe( - 'custom_plugin', - ); - }); - }); -}); diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts deleted file mode 100644 index 8a4a4b50fa..0000000000 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Config, ConfigReader } from '@backstage/config'; -import { JsonObject } from '@backstage/types'; -import { Knex } from 'knex'; -import { merge, omit } from 'lodash'; -import { mergeDatabaseConfig } from './config'; -import { - createDatabaseClient, - createNameOverride, - createSchemaOverride, - ensureDatabaseExists, - ensureSchemaExists, - normalizeConnection, -} from './connection'; -import { PluginDatabaseManager } from './types'; -import path from 'path'; -import { - DatabaseService, - LifecycleService, - LoggerService, - PluginMetadataService, -} from '@backstage/backend-plugin-api'; -import { stringifyError } from '@backstage/errors'; - -/** - * Provides a config lookup path for a plugin's config block. - */ -function pluginPath(pluginId: string): string { - return `plugin.${pluginId}`; -} - -/** - * Creation options for {@link DatabaseManager}. - * - * @public - */ -export type DatabaseManagerOptions = { - migrations?: PluginDatabaseManager['migrations']; - logger?: LoggerService; -}; - -/** - * An interface that represents the legacy global DatabaseManager implementation. - * @public - */ -export type LegacyRootDatabaseService = { - forPlugin(pluginId: string): DatabaseService; -}; - -/** - * Manages database connections for Backstage backend plugins. - * - * @public - * @remarks - * - * The database manager allows the user to set connection and client settings on - * a per pluginId basis by defining a database config block under - * `plugin.` in addition to top level defaults. Optionally, a user may - * set `prefix` which is used to prefix generated database names if config is - * not provided. - */ -export class DatabaseManager implements LegacyRootDatabaseService { - /** - * Creates a {@link DatabaseManager} from `backend.database` config. - * - * @param config - The loaded application configuration. - * @param options - An optional configuration object. - */ - static fromConfig( - config: Config, - options?: DatabaseManagerOptions, - ): DatabaseManager { - const databaseConfig = config.getConfig('backend.database'); - - return new DatabaseManager( - databaseConfig, - databaseConfig.getOptionalString('prefix'), - options, - ); - } - - private constructor( - private readonly config: Config, - private readonly prefix: string = 'backstage_plugin_', - private readonly options?: DatabaseManagerOptions, - private readonly databaseCache: Map> = new Map(), - ) {} - - /** - * Generates a PluginDatabaseManager for consumption by plugins. - * - * @param pluginId - The plugin that the database manager should be created for. Plugin names - * should be unique as they are used to look up database config overrides under - * `backend.database.plugin`. - */ - forPlugin( - pluginId: string, - deps?: { - lifecycle: LifecycleService; - pluginMetadata: PluginMetadataService; - }, - ): PluginDatabaseManager { - const getClient = () => this.getDatabase(pluginId, deps); - const migrations = { skip: false, ...this.options?.migrations }; - return { getClient, migrations }; - } - - /** - * Provides the canonical database name for a given plugin. - * - * This method provides the effective database name which is determined using global - * and plugin specific database config. If no explicit database name is configured - * and `pluginDivisionMode` is not `schema`, this method will provide a generated name - * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is - * `schema`, it will fallback to using the default database for the knex instance. - * - * @param pluginId - Lookup the database name for given plugin - * @returns String representing the plugin's database name - */ - private getDatabaseName(pluginId: string): string | undefined { - const connection = this.getConnectionConfig(pluginId); - - if (this.getClientType(pluginId).client.includes('sqlite3')) { - const sqliteFilename: string | undefined = ( - connection as Knex.Sqlite3ConnectionConfig - ).filename; - - if (sqliteFilename === ':memory:') { - return sqliteFilename; - } - - const sqliteDirectory = - (connection as { directory?: string }).directory ?? '.'; - - return path.join(sqliteDirectory, sqliteFilename ?? `${pluginId}.sqlite`); - } - - const databaseName = (connection as Knex.ConnectionConfig)?.database; - - // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied or fallback to default knex database - if (this.getPluginDivisionModeConfig() === 'schema') { - return databaseName; - } - - // all other supported databases should fallback to an auto-prefixed name - return databaseName ?? `${this.prefix}${pluginId}`; - } - - /** - * Provides the client type which should be used for a given plugin. - * - * The client type is determined by plugin specific config if present. - * Otherwise the base client is used as the fallback. - * - * @param pluginId - Plugin to get the client type for - * @returns Object with client type returned as `client` and boolean - * representing whether or not the client was overridden as - * `overridden` - */ - private getClientType(pluginId: string): { - client: string; - overridden: boolean; - } { - const pluginClient = this.config.getOptionalString( - `${pluginPath(pluginId)}.client`, - ); - - const baseClient = this.config.getString('client'); - const client = pluginClient ?? baseClient; - return { - client, - overridden: client !== baseClient, - }; - } - - private getRoleConfig(pluginId: string): string | undefined { - return ( - this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ?? - this.config.getOptionalString('role') - ); - } - - /** - * Provides the knexConfig which should be used for a given plugin. - * - * @param pluginId - Plugin to get the knexConfig for - * @returns The merged knexConfig value or undefined if it isn't specified - */ - private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined { - const pluginConfig = this.config - .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`) - ?.get(); - - const baseConfig = this.config - .getOptionalConfig('knexConfig') - ?.get(); - - return merge(baseConfig, pluginConfig); - } - - private getEnsureExistsConfig(pluginId: string): boolean { - const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true; - return ( - this.config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ?? - baseConfig - ); - } - - private getPluginDivisionModeConfig(): string { - return this.config.getOptionalString('pluginDivisionMode') ?? 'database'; - } - - /** - * Provides a Knex connection plugin config by combining base and plugin - * config. - * - * This method provides a baseConfig for a plugin database connector. If the - * client type has not been overridden, the global connection config will be - * included with plugin specific config as the base. Values from the plugin - * connection take precedence over the base. Base database name is omitted for - * all supported databases excluding SQLite unless `pluginDivisionMode` is set - * to `schema`. - */ - private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig { - const { client, overridden } = this.getClientType(pluginId); - - let baseConnection = normalizeConnection( - this.config.get('connection'), - this.config.getString('client'), - ); - - if ( - client.includes('sqlite3') && - 'filename' in baseConnection && - baseConnection.filename !== ':memory:' - ) { - throw new Error( - '`connection.filename` is not supported for the base sqlite connection. Prefer `connection.directory` or provide a filename for the plugin connection instead.', - ); - } - - // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The - // `database` property from the base connection is omitted unless `pluginDivisionMode` - // is set to `schema`. SQLite3's `filename` property is an exception as this is used as a - // directory elsewhere so we preserve `filename`. - if (this.getPluginDivisionModeConfig() !== 'schema') { - baseConnection = omit(baseConnection, 'database'); - } - - // get and normalize optional plugin specific database connection - const connection = normalizeConnection( - this.config.getOptional(`${pluginPath(pluginId)}.connection`), - client, - ); - - if (client === 'pg') { - ( - baseConnection as Knex.PgConnectionConfig - ).application_name ||= `backstage_plugin_${pluginId}`; - } - - return { - // include base connection if client type has not been overridden - ...(overridden ? {} : baseConnection), - ...connection, - } as Knex.StaticConnectionConfig; - } - - /** - * Provides a Knex database config for a given plugin. - * - * This method provides a Knex configuration object along with the plugin's - * client type. - * - * @param pluginId - The plugin that the database config should correspond with - */ - private getConfigForPlugin(pluginId: string): Knex.Config { - const { client } = this.getClientType(pluginId); - const role = this.getRoleConfig(pluginId); - - return { - ...this.getAdditionalKnexConfig(pluginId), - client, - connection: this.getConnectionConfig(pluginId), - ...(role && { role }), - }; - } - - /** - * Provides a partial `Knex.Config` database schema override for a given - * plugin. - * - * @param pluginId - Target plugin to get database schema override - * @returns Partial `Knex.Config` with database schema override - */ - private getSchemaOverrides(pluginId: string): Knex.Config | undefined { - return createSchemaOverride(this.getClientType(pluginId).client, pluginId); - } - - /** - * Provides a partial `Knex.Config`• database name override for a given plugin. - * - * @param pluginId - Target plugin to get database name override - * @returns Partial `Knex.Config` with database name override - */ - private getDatabaseOverrides(pluginId: string): Knex.Config { - const databaseName = this.getDatabaseName(pluginId); - return databaseName - ? createNameOverride(this.getClientType(pluginId).client, databaseName) - : {}; - } - - /** - * Provides a scoped Knex client for a plugin as per application config. - * - * @param pluginId - Plugin to get a Knex client for - * @returns Promise which resolves to a scoped Knex database client for a - * plugin - */ - private async getDatabase( - pluginId: string, - deps?: { - lifecycle: LifecycleService; - pluginMetadata: PluginMetadataService; - }, - ): Promise { - if (this.databaseCache.has(pluginId)) { - return this.databaseCache.get(pluginId)!; - } - - const clientPromise = Promise.resolve().then(async () => { - const pluginConfig = new ConfigReader( - this.getConfigForPlugin(pluginId) as JsonObject, - ); - - const databaseName = this.getDatabaseName(pluginId); - if (databaseName && this.getEnsureExistsConfig(pluginId)) { - try { - await ensureDatabaseExists(pluginConfig, databaseName); - } catch (error) { - throw new Error( - `Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`, - ); - } - } - - let schemaOverrides; - if (this.getPluginDivisionModeConfig() === 'schema') { - schemaOverrides = this.getSchemaOverrides(pluginId); - if (this.getEnsureExistsConfig(pluginId)) { - try { - await ensureSchemaExists(pluginConfig, pluginId); - } catch (error) { - throw new Error( - `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`, - ); - } - } - } - - const databaseClientOverrides = mergeDatabaseConfig( - {}, - this.getDatabaseOverrides(pluginId), - schemaOverrides, - ); - - const client = createDatabaseClient( - pluginConfig, - databaseClientOverrides, - deps, - ); - if (process.env.NODE_ENV !== 'test') { - this.startKeepaliveLoop(pluginId, client); - } - return client; - }); - - this.databaseCache.set(pluginId, clientPromise); - - return clientPromise; - } - - private startKeepaliveLoop(pluginId: string, client: Knex): void { - let lastKeepaliveFailed = false; - - setInterval(() => { - // During testing it can happen that the environment is torn down and - // this client is `undefined`, but this interval is still run. - client?.raw('select 1').then( - () => { - lastKeepaliveFailed = false; - }, - (error: unknown) => { - if (!lastKeepaliveFailed) { - lastKeepaliveFailed = true; - this.options?.logger?.warn( - `Database keepalive failed for plugin ${pluginId}, ${stringifyError( - error, - )}`, - ); - } - }, - ); - }, 60 * 1000); - } -} diff --git a/packages/backend-common/src/database/connection.test.ts b/packages/backend-common/src/database/connection.test.ts deleted file mode 100644 index 3028d46cae..0000000000 --- a/packages/backend-common/src/database/connection.test.ts +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ConfigReader } from '@backstage/config'; -import { - createDatabaseClient, - createNameOverride, - createSchemaOverride, - dropDatabase, - ensureSchemaExists, - parseConnectionString, -} from './connection'; -import { mysqlConnector, pgConnector } from './connectors'; - -const mocked = (f: Function) => f as jest.Mock; - -jest.mock('./connectors', () => { - const connectors = jest.requireActual('./connectors'); - return { - ...connectors, - mysqlConnector: { - ...connectors.mysqlConnector, - dropDatabase: jest.fn(), - }, - pgConnector: { - ...connectors.pgConnector, - dropDatabase: jest.fn(), - ensureSchemaExists: jest.fn(), - }, - }; -}); - -describe('database connection', () => { - describe('createDatabaseClient', () => { - it('returns a postgres connection', () => { - expect( - createDatabaseClient( - new ConfigReader({ - client: 'pg', - connection: { - host: 'acme', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }), - ), - ).toBeTruthy(); - }); - - it('returns an sqlite connection', () => { - expect( - createDatabaseClient( - new ConfigReader({ - client: 'better-sqlite3', - connection: ':memory:', - }), - ), - ).toBeTruthy(); - }); - - it('returns a mysql connection', () => { - expect(() => - createDatabaseClient( - new ConfigReader({ - client: 'mysql2', - connection: { - host: '127.0.0.1', - user: 'foo', - password: 'bar', - database: 'dbname', - }, - }), - ), - ).toBeTruthy(); - }); - - it('accepts overrides', () => { - expect( - createDatabaseClient( - new ConfigReader({ - client: 'pg', - connection: { - host: 'acme', - user: 'foo', - password: 'bar', - database: 'foodb', - }, - }), - { - connection: { - database: 'foo', - }, - }, - ), - ).toBeTruthy(); - }); - - it('throws an error without a client', () => { - expect(() => - createDatabaseClient( - new ConfigReader({ - connection: '', - }), - ), - ).toThrow(); - }); - - it('throws an error without a connection', () => { - expect(() => - createDatabaseClient( - new ConfigReader({ - client: 'pg', - }), - ), - ).toThrow(); - }); - }); - - describe('createNameOverride', () => { - it('returns Knex config for postgres', () => { - expect(createNameOverride('pg', 'testpg')).toHaveProperty( - 'connection.database', - 'testpg', - ); - }); - - it('returns Knex config for sqlite', () => { - expect(createNameOverride('better-sqlite3', 'testsqlite')).toHaveProperty( - 'connection.filename', - 'testsqlite', - ); - }); - - it('returns Knex config for mysql', () => { - expect(createNameOverride('mysql', 'testmysql')).toHaveProperty( - 'connection.database', - 'testmysql', - ); - }); - - it('throws an error for unknown connection', () => { - expect(() => createNameOverride('unknown', 'testname')).toThrow(); - }); - }); - - describe('parseConnectionString', () => { - it('returns parsed Knex.StaticConnectionConfig for postgres', () => { - expect( - parseConnectionString('postgresql://foo:bar@acme:5432/foodb', 'pg'), - ).toHaveProperty('database', 'foodb'); - }); - - it('returns parsed Knex.StaticConnectionConfig for mysql2', () => { - expect( - parseConnectionString('mysql://foo:bar@acme:3306/foodb', 'mysql2'), - ).toHaveProperty('database', 'foodb'); - }); - - it('throws an error if client hint is not provided', () => { - expect(() => parseConnectionString('sqlite://')).toThrow(); - }); - }); - - describe('createSchemaOverride', () => { - it('returns Knex config for postgres', () => { - expect(createSchemaOverride('pg', 'testpg')).toHaveProperty( - 'searchPath', - ['testpg'], - ); - }); - - it('throws error for sqlite', () => { - expect( - createSchemaOverride('better-sqlite3', 'testsqlite'), - ).toBeUndefined(); - }); - - it('returns Knex config for mysql', () => { - expect(createSchemaOverride('mysql', 'testmysql')).toBeUndefined(); - }); - - it('throws an error for unknown connection', () => { - expect(createSchemaOverride('unknown', 'testname')).toBeUndefined(); - }); - }); - - describe('ensureSchemaExists', () => { - it('returns successfully with pg client', async () => { - await ensureSchemaExists( - new ConfigReader({ - client: 'pg', - schema: 'catalog', - connection: 'postgresql://testuser:testpass@acme:5432/userdbname', - }), - 'catalog', - ); - - const mockCalls = mocked( - pgConnector.ensureSchemaExists as Function, - ).mock.calls.splice(-1); - const [baseConfig, schemaName] = mockCalls[0]; - - expect(baseConfig.get()).toMatchObject({ - client: 'pg', - connection: 'postgresql://testuser:testpass@acme:5432/userdbname', - }); - - expect(schemaName).toEqual('catalog'); - }); - - it('throws error for non pg client', () => { - return expect( - ensureSchemaExists( - new ConfigReader({ - client: 'better-sqlite3', - schema: 'catalog', - connection: ':memory:', - }), - 'catalog', - ), - ).resolves.toBeUndefined(); - }); - }); - - describe('dropDatabase', () => { - it('returns successfully with pg client', async () => { - await dropDatabase( - new ConfigReader({ - client: 'pg', - schema: 'catalog', - connection: 'postgresql://testuser:testpass@acme:5432/userdbname', - }), - 'backstage_plugin_foobar', - ); - - const mockCalls = mocked( - pgConnector.dropDatabase as Function, - ).mock.calls.splice(-1); - const [baseConfig, databaseName] = mockCalls[0]; - - expect(baseConfig.get()).toMatchObject({ - client: 'pg', - connection: 'postgresql://testuser:testpass@acme:5432/userdbname', - }); - - expect(databaseName).toEqual('backstage_plugin_foobar'); - }); - - it('returns successfully with mysql client', async () => { - await dropDatabase( - new ConfigReader({ - client: 'mysql2', - connection: { - host: '127.0.0.1', - user: 'foo', - password: 'bar', - database: 'dbname', - }, - }), - 'backstage_plugin_foobar', - ); - - const mockCalls = mocked( - mysqlConnector.dropDatabase as Function, - ).mock.calls.splice(-1); - const [baseConfig, databaseName] = mockCalls[0]; - - expect(baseConfig.get()).toMatchObject({ - client: 'mysql2', - connection: { - host: '127.0.0.1', - user: 'foo', - password: 'bar', - database: 'dbname', - }, - }); - - expect(databaseName).toEqual('backstage_plugin_foobar'); - }); - - it('does nothing in other database drivers', () => { - return expect( - dropDatabase( - new ConfigReader({ - client: 'better-sqlite3', - schema: 'catalog', - connection: ':memory:', - }), - 'catalog', - ), - ).resolves.toBeUndefined(); - }); - }); -}); diff --git a/packages/backend-common/src/database/connection.ts b/packages/backend-common/src/database/connection.ts deleted file mode 100644 index c0e031516f..0000000000 --- a/packages/backend-common/src/database/connection.ts +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Config } from '@backstage/config'; -import { JsonObject } from '@backstage/types'; -import { InputError } from '@backstage/errors'; -import knexFactory, { Knex } from 'knex'; -import limiterFactory from 'p-limit'; -import { mergeDatabaseConfig } from './config'; -import { DatabaseConnector } from './types'; - -import { mysqlConnector, pgConnector, sqlite3Connector } from './connectors'; -import { - LifecycleService, - PluginMetadataService, -} from '@backstage/backend-plugin-api'; - -type DatabaseClient = - | 'pg' - | 'better-sqlite3' - | 'sqlite3' - | 'mysql' - | 'mysql2' - | string; - -// This limits the number of concurrent CREATE DATABASE and CREATE SCHEMA -// commands, globally, to just one. This is overly defensive, and was added as -// an attempt to counteract the pool issues on recent node versions. See -// https://github.com/backstage/backstage/pull/19988 -const ddlLimiter = limiterFactory(1); - -/** - * Mapping of client type to supported database connectors - * - * Database connectors can be aliased here, for example mysql2 uses - * the same connector as mysql. - */ -const ConnectorMapping: Record = { - pg: pgConnector, - 'better-sqlite3': sqlite3Connector, - sqlite3: sqlite3Connector, - mysql: mysqlConnector, - mysql2: mysqlConnector, -}; - -/** - * Creates a knex database connection - * - * @public - * @param dbConfig - The database config - * @param overrides - Additional options to merge with the config - */ -export function createDatabaseClient( - dbConfig: Config, - overrides?: Partial, - deps?: { - lifecycle: LifecycleService; - pluginMetadata: PluginMetadataService; - }, -) { - const client: DatabaseClient = dbConfig.getString('client'); - - return ( - ConnectorMapping[client]?.createClient(dbConfig, overrides, deps) ?? - knexFactory(mergeDatabaseConfig(dbConfig.get(), overrides)) - ); -} - -/** - * Ensures that the given databases all exist, creating them if they do not. - * - * @public - */ -export async function ensureDatabaseExists( - dbConfig: Config, - ...databases: Array -): Promise { - const client: DatabaseClient = dbConfig.getString('client'); - - return await ddlLimiter(() => - ConnectorMapping[client]?.ensureDatabaseExists?.(dbConfig, ...databases), - ); -} - -/** - * Drops the given databases. - * - * @public - */ -export async function dropDatabase( - dbConfig: Config, - ...databases: Array -): Promise { - const client: DatabaseClient = dbConfig.getString('client'); - - return await ddlLimiter(() => - ConnectorMapping[client]?.dropDatabase?.(dbConfig, ...databases), - ); -} - -/** - * Ensures that the given schemas all exist, creating them if they do not. - * - * @public - */ -export async function ensureSchemaExists( - dbConfig: Config, - ...schemas: Array -): Promise { - const client: DatabaseClient = dbConfig.getString('client'); - - return await ddlLimiter(() => - ConnectorMapping[client]?.ensureSchemaExists?.(dbConfig, ...schemas), - ); -} - -/** - * Provides a `Knex.Config` object with the provided database name for a given - * client. - */ -export function createNameOverride( - client: string, - name: string, -): Partial { - try { - return ConnectorMapping[client].createNameOverride(name); - } catch (e) { - throw new InputError( - `Unable to create database name override for '${client}' connector`, - e, - ); - } -} - -/** - * Provides a `Knex.Config` object with the provided database schema for a given - * client. Currently only supported by `pg`. - */ -export function createSchemaOverride( - client: string, - name: string, -): Partial { - try { - return ConnectorMapping[client]?.createSchemaOverride?.(name); - } catch (e) { - throw new InputError( - `Unable to create database schema override for '${client}' connector`, - e, - ); - } -} - -/** - * Parses a connection string for a given client and provides a connection config. - */ -export function parseConnectionString( - connectionString: string, - client?: string, -): Knex.StaticConnectionConfig { - if (typeof client === 'undefined' || client === null) { - throw new InputError( - 'Database connection string client type auto-detection is not yet supported.', - ); - } - - try { - return ConnectorMapping[client].parseConnectionString(connectionString); - } catch (e) { - throw new InputError( - `Unable to parse connection string for '${client}' connector`, - ); - } -} - -/** - * Normalizes a connection config or string into an object which can be passed - * to Knex. - */ -export function normalizeConnection( - connection: Knex.StaticConnectionConfig | JsonObject | string | undefined, - client: string, -): Partial { - if (typeof connection === 'undefined' || connection === null) { - return {}; - } - - return typeof connection === 'string' || connection instanceof String - ? parseConnectionString(connection as string, client) - : connection; -} diff --git a/packages/backend-common/src/database/connectors/mysql.ts b/packages/backend-common/src/database/connectors/mysql.ts deleted file mode 100644 index a4bac3f7e1..0000000000 --- a/packages/backend-common/src/database/connectors/mysql.ts +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import knexFactory, { Knex } from 'knex'; -import yn from 'yn'; - -import { Config } from '@backstage/config'; -import { InputError } from '@backstage/errors'; -import { mergeDatabaseConfig } from '../config'; -import { DatabaseConnector } from '../types'; -import defaultNameOverride from './defaultNameOverride'; - -/** - * Creates a knex mysql database connection - * - * @param dbConfig - The database config - * @param overrides - Additional options to merge with the config - */ -export function createMysqlDatabaseClient( - dbConfig: Config, - overrides?: Knex.Config, -) { - const knexConfig = buildMysqlDatabaseConfig(dbConfig, overrides); - const database = knexFactory(knexConfig); - return database; -} - -/** - * Builds a knex mysql database connection - * - * @param dbConfig - The database config - * @param overrides - Additional options to merge with the config - */ -export function buildMysqlDatabaseConfig( - dbConfig: Config, - overrides?: Knex.Config, -) { - return mergeDatabaseConfig( - dbConfig.get(), - { - connection: getMysqlConnectionConfig(dbConfig, !!overrides), - useNullAsDefault: true, - }, - overrides, - ); -} - -/** - * Gets the mysql connection config - * - * @param dbConfig - The database config - * @param parseConnectionString - Flag to explicitly control connection string parsing - */ -export function getMysqlConnectionConfig( - dbConfig: Config, - parseConnectionString?: boolean, -): Knex.MySqlConnectionConfig | string { - const connection = dbConfig.get('connection') as any; - const isConnectionString = - typeof connection === 'string' || connection instanceof String; - const autoParse = typeof parseConnectionString !== 'boolean'; - - const shouldParseConnectionString = autoParse - ? isConnectionString - : parseConnectionString && isConnectionString; - - return shouldParseConnectionString - ? parseMysqlConnectionString(connection as string) - : connection; -} - -/** - * Parses a mysql connection string. - * - * e.g. mysql://examplename:somepassword@examplehost:3306/dbname - * @param connectionString - The mysql connection string - */ -export function parseMysqlConnectionString( - connectionString: string, -): Knex.MySqlConnectionConfig { - try { - const { - protocol, - username, - password, - port, - hostname, - pathname, - searchParams, - } = new URL(connectionString); - - if (protocol !== 'mysql:') { - throw new Error(`Unknown protocol ${protocol}`); - } else if (!username || !password) { - throw new Error(`Missing username/password`); - } else if (!pathname.match(/^\/[^/]+$/)) { - throw new Error(`Expected single path segment`); - } - - const result: Knex.MySqlConnectionConfig = { - user: username, - password, - host: hostname, - port: Number(port || 3306), - database: decodeURIComponent(pathname.substring(1)), - }; - - const ssl = searchParams.get('ssl'); - if (ssl) { - result.ssl = ssl; - } - - const debug = searchParams.get('debug'); - if (debug) { - result.debug = yn(debug); - } - - return result; - } catch (e) { - throw new InputError( - `Error while parsing MySQL connection string, ${e}`, - e, - ); - } -} - -/** - * Creates the missing mysql database if it does not exist - * - * @param dbConfig - The database config - * @param databases - The names of the databases to create - */ -export async function ensureMysqlDatabaseExists( - dbConfig: Config, - ...databases: Array -) { - const admin = createMysqlDatabaseClient(dbConfig, { - connection: { - database: null as unknown as string, - }, - pool: { - min: 0, - acquireTimeoutMillis: 10000, - }, - }); - - try { - const ensureDatabase = async (database: string) => { - await admin.raw(`CREATE DATABASE IF NOT EXISTS ??`, [database]); - }; - await Promise.all( - databases.map(async database => { - // For initial setup we use a smaller timeout but several retries. Given that this - // is a separate connection pool we should never really run into issues with connection - // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency. - let lastErr: Error | undefined = undefined; - for (let i = 0; i < 3; i++) { - try { - return await ensureDatabase(database); - } catch (err) { - lastErr = err; - } - await new Promise(resolve => setTimeout(resolve, 100)); - } - throw lastErr; - }), - ); - } finally { - await admin.destroy(); - } -} - -/** - * Drops the given mysql databases. - * - * @param dbConfig - The database config - * @param databases - The names of the databases to create - */ -export async function dropMysqlDatabase( - dbConfig: Config, - ...databases: Array -) { - const admin = createMysqlDatabaseClient(dbConfig, { - connection: { - database: null as unknown as string, - }, - pool: { - min: 0, - acquireTimeoutMillis: 10000, - }, - }); - - try { - const dropDatabase = async (database: string) => { - await admin.raw(`DROP DATABASE ??`, [database]); - }; - await Promise.all( - databases.map(async database => { - return await dropDatabase(database); - }), - ); - } finally { - await admin.destroy(); - } -} - -/** - * MySQL database connector. - * - * Exposes database connector functionality via an immutable object. - */ -export const mysqlConnector: DatabaseConnector = Object.freeze({ - createClient: createMysqlDatabaseClient, - ensureDatabaseExists: ensureMysqlDatabaseExists, - createNameOverride: defaultNameOverride, - parseConnectionString: parseMysqlConnectionString, - dropDatabase: dropMysqlDatabase, -}); diff --git a/packages/backend-common/src/database/connectors/postgres.ts b/packages/backend-common/src/database/connectors/postgres.ts deleted file mode 100644 index dc9b19f6ad..0000000000 --- a/packages/backend-common/src/database/connectors/postgres.ts +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import knexFactory, { Knex } from 'knex'; - -import { Config } from '@backstage/config'; -import { ForwardedError } from '@backstage/errors'; -import { mergeDatabaseConfig } from '../config'; -import { DatabaseConnector } from '../types'; -import defaultNameOverride from './defaultNameOverride'; -import defaultSchemaOverride from './defaultSchemaOverride'; -import { Client } from 'pg'; - -/** - * Creates a knex postgres database connection - * - * @param dbConfig - The database config - * @param overrides - Additional options to merge with the config - */ -export function createPgDatabaseClient( - dbConfig: Config, - overrides?: Knex.Config, -) { - const knexConfig = buildPgDatabaseConfig(dbConfig, overrides); - const database = knexFactory(knexConfig); - - const role = dbConfig.getOptionalString('role'); - - if (role) { - database.client.pool.on( - 'createSuccess', - async (_event: number, pgClient: Client) => { - await pgClient.query(`SET ROLE ${role}`); - }, - ); - } - return database; -} - -/** - * Builds a knex postgres database connection - * - * @param dbConfig - The database config - * @param overrides - Additional options to merge with the config - */ -export function buildPgDatabaseConfig( - dbConfig: Config, - overrides?: Knex.Config, -) { - return mergeDatabaseConfig( - dbConfig.get(), - { - connection: getPgConnectionConfig(dbConfig, !!overrides), - useNullAsDefault: true, - }, - overrides, - ); -} - -/** - * Gets the postgres connection config - * - * @param dbConfig - The database config - * @param parseConnectionString - Flag to explicitly control connection string parsing - */ -export function getPgConnectionConfig( - dbConfig: Config, - parseConnectionString?: boolean, -): Knex.PgConnectionConfig | string { - const connection = dbConfig.get('connection') as any; - const isConnectionString = - typeof connection === 'string' || connection instanceof String; - const autoParse = typeof parseConnectionString !== 'boolean'; - - const shouldParseConnectionString = autoParse - ? isConnectionString - : parseConnectionString && isConnectionString; - - return shouldParseConnectionString - ? parsePgConnectionString(connection as string) - : connection; -} - -/** - * Parses a connection string using pg-connection-string - * - * @param connectionString - The postgres connection string - */ -export function parsePgConnectionString(connectionString: string) { - const parse = requirePgConnectionString(); - return parse(connectionString); -} - -function requirePgConnectionString() { - try { - return require('pg-connection-string').parse; - } catch (e) { - throw new ForwardedError("Postgres: Install 'pg-connection-string'", e); - } -} - -/** - * Creates the missing Postgres database if it does not exist - * - * @param dbConfig - The database config - * @param databases - The name of the databases to create - */ -export async function ensurePgDatabaseExists( - dbConfig: Config, - ...databases: Array -) { - const admin = createPgDatabaseClient(dbConfig, { - connection: { - database: 'postgres', - }, - pool: { - min: 0, - acquireTimeoutMillis: 10000, - }, - }); - - try { - const ensureDatabase = async (database: string) => { - const result = await admin - .from('pg_database') - .where('datname', database) - .count>(); - - if (parseInt(result[0].count, 10) > 0) { - return; - } - - await admin.raw(`CREATE DATABASE ??`, [database]); - }; - - await Promise.all( - databases.map(async database => { - // For initial setup we use a smaller timeout but several retries. Given that this - // is a separate connection pool we should never really run into issues with connection - // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency. - let lastErr: Error | undefined = undefined; - for (let i = 0; i < 3; i++) { - try { - return await ensureDatabase(database); - } catch (err) { - lastErr = err; - } - await new Promise(resolve => setTimeout(resolve, 100)); - } - throw lastErr; - }), - ); - } finally { - await admin.destroy(); - } -} - -/** - * Creates the missing Postgres schema if it does not exist - * - * @param dbConfig - The database config - * @param schemas - The name of the schemas to create - */ -export async function ensurePgSchemaExists( - dbConfig: Config, - ...schemas: Array -): Promise { - const admin = createPgDatabaseClient(dbConfig); - const role = dbConfig.getOptionalString('role'); - - try { - const ensureSchema = async (database: string) => { - if (role) { - await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [ - database, - role, - ]); - } else { - await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]); - } - }; - - await Promise.all(schemas.map(ensureSchema)); - } finally { - await admin.destroy(); - } -} - -/** - * Drops the Postgres databases. - * - * @param dbConfig - The database config - * @param databases - The name of the databases to drop - */ -export async function dropPgDatabase( - dbConfig: Config, - ...databases: Array -) { - const admin = createPgDatabaseClient(dbConfig); - await Promise.all( - databases.map(async database => { - await admin.raw(`DROP DATABASE ??`, [database]); - }), - ); -} - -/** - * PostgreSQL database connector. - * - * Exposes database connector functionality via an immutable object. - */ -export const pgConnector: DatabaseConnector = Object.freeze({ - createClient: createPgDatabaseClient, - ensureDatabaseExists: ensurePgDatabaseExists, - ensureSchemaExists: ensurePgSchemaExists, - createNameOverride: defaultNameOverride, - createSchemaOverride: defaultSchemaOverride, - parseConnectionString: parsePgConnectionString, - dropDatabase: dropPgDatabase, -}); diff --git a/packages/backend-common/src/database/connectors/sqlite3.ts b/packages/backend-common/src/database/connectors/sqlite3.ts deleted file mode 100644 index 3cb0f57de6..0000000000 --- a/packages/backend-common/src/database/connectors/sqlite3.ts +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Config } from '@backstage/config'; -import { ensureDirSync } from 'fs-extra'; -import knexFactory, { Knex } from 'knex'; -import path from 'path'; -import { DevDataStore } from '@backstage/backend-dev-utils'; -import { mergeDatabaseConfig } from '../config'; -import { DatabaseConnector } from '../types'; -import { - LifecycleService, - PluginMetadataService, -} from '@backstage/backend-plugin-api'; - -/** - * Creates a knex SQLite3 database connection - * - * @param dbConfig - The database config - * @param overrides - Additional options to merge with the config - */ -export function createSqliteDatabaseClient( - dbConfig: Config, - overrides?: Knex.Config, - deps?: { - lifecycle: LifecycleService; - pluginMetadata: PluginMetadataService; - }, -) { - const knexConfig = buildSqliteDatabaseConfig(dbConfig, overrides); - const connConfig = knexConfig.connection as Knex.Sqlite3ConnectionConfig; - - const filename = connConfig.filename ?? ':memory:'; - - // If storage on disk is used, ensure that the directory exists - if (filename !== ':memory:') { - const directory = path.dirname(filename); - ensureDirSync(directory); - } - - let database: Knex; - - if (deps && filename === ':memory:') { - // The dev store is used during watch mode to store and restore the database - // across reloads. It is only available when running the backend through - // `backstage-cli package start`. - const devStore = DevDataStore.get(); - - if (devStore) { - const dataKey = `sqlite3-db-${deps.pluginMetadata.getId()}`; - - const connectionLoader = async () => { - // If seed data is available, use it tconnectionLoader restore the database - const { data: seedData } = await devStore.load(dataKey); - - return { - ...(knexConfig.connection as Knex.Sqlite3ConnectionConfig), - filename: seedData ?? ':memory:', - }; - }; - - database = knexFactory({ - ...knexConfig, - connection: Object.assign(connectionLoader, { - // This is a workaround for the knex SQLite driver always warning when using a config loader - filename: ':memory:', - }), - }); - - // If the dev store is available we save the database state on shutdown - deps.lifecycle.addShutdownHook(async () => { - const connection = await database.client.acquireConnection(); - const data = connection.serialize(); - await devStore.save(dataKey, data); - }); - } else { - database = knexFactory(knexConfig); - } - } else { - database = knexFactory(knexConfig); - } - - database.client.pool.on('createSuccess', (_eventId: any, resource: any) => { - resource.run('PRAGMA foreign_keys = ON', () => {}); - }); - - return database; -} - -/** - * Builds a knex SQLite3 connection config - * - * @param dbConfig - The database config - * @param overrides - Additional options to merge with the config - */ -export function buildSqliteDatabaseConfig( - dbConfig: Config, - overrides?: Knex.Config, -): Knex.Config { - const baseConfig = dbConfig.get(); - - // Normalize config to always contain a connection object - if (typeof baseConfig.connection === 'string') { - baseConfig.connection = { filename: baseConfig.connection }; - } - if (overrides && typeof overrides.connection === 'string') { - overrides.connection = { filename: overrides.connection }; - } - - const config: Knex.Config = mergeDatabaseConfig( - { - connection: {}, - }, - baseConfig, - { - useNullAsDefault: true, - }, - overrides, - ); - - return config; -} - -/** - * Provides a partial knex SQLite3 config to override database name. - */ -export function createSqliteNameOverride(name: string): Partial { - return { - connection: parseSqliteConnectionString(name), - }; -} - -/** - * Produces a partial knex SQLite3 connection config with database name. - */ -export function parseSqliteConnectionString( - name: string, -): Knex.Sqlite3ConnectionConfig { - return { - filename: name, - }; -} - -/** - * SQLite3 database connector. - * - * Exposes database connector functionality via an immutable object. - */ -export const sqlite3Connector: DatabaseConnector = Object.freeze({ - createClient: createSqliteDatabaseClient, - createNameOverride: createSqliteNameOverride, - parseConnectionString: parseSqliteConnectionString, -}); diff --git a/packages/backend-common/src/database/index.ts b/packages/backend-common/src/database/index.ts index 330429f0ef..0e95261d82 100644 --- a/packages/backend-common/src/database/index.ts +++ b/packages/backend-common/src/database/index.ts @@ -14,17 +14,5 @@ * limitations under the License. */ -export * from './DatabaseManager'; - -/* - * Undocumented API surface from connection is being reduced for future deprecation. - * Avoid exporting additional symbols. - */ -export { - createDatabaseClient, - ensureDatabaseExists, - dropDatabase, -} from './connection'; - +export * from './reexport'; export type { PluginDatabaseManager } from './types'; -export { isDatabaseConflictError } from './util'; diff --git a/packages/backend-common/src/database/reexport.ts b/packages/backend-common/src/database/reexport.ts new file mode 100644 index 0000000000..1ecff9be15 --- /dev/null +++ b/packages/backend-common/src/database/reexport.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/* + * NOTE(freben): This is a temporary hack. We use cross-package imports so that + * we do not have to maintain double implementations for the time being, until + * backend-common is properly removed. When it is, the impleemntation should be + * moved into this part of the repo instead. + */ + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { + DatabaseManager, + dropDatabase, + type DatabaseManagerOptions, + type LegacyRootDatabaseService, +} from '../../../backend-defaults/src/entrypoints/database/DatabaseManager'; + +export { + DatabaseManager, + dropDatabase, + type DatabaseManagerOptions, + type LegacyRootDatabaseService, +}; diff --git a/packages/backend-common/src/database/types.ts b/packages/backend-common/src/database/types.ts index 3e9832aec5..a9cceaa1f9 100644 --- a/packages/backend-common/src/database/types.ts +++ b/packages/backend-common/src/database/types.ts @@ -24,11 +24,11 @@ import { Knex } from 'knex'; export type { DatabaseService as PluginDatabaseManager } from '@backstage/backend-plugin-api'; /** - * DatabaseConnector manages an underlying Knex database driver. + * Manages an underlying Knex database driver. */ export interface DatabaseConnector { /** - * createClient provides an instance of a knex database connector. + * Provides an instance of a knex database connector. */ createClient( dbConfig: Config, @@ -38,27 +38,29 @@ export interface DatabaseConnector { pluginMetadata: PluginMetadataService; }, ): Knex; + /** - * createNameOverride provides a partial knex config sufficient to override a - * database name. + * Provides a partial knex config sufficient to override a database name. */ createNameOverride(name: string): Partial; + /** - * createSchemaOverride provides a partial knex config sufficient to override a - * PostgreSQL schema name within utilizing the `searchPath` knex configuration. + * Provides a partial knex config sufficient to override a PostgreSQL schema + * name within utilizing the `searchPath` knex configuration. */ createSchemaOverride?(name: string): Partial; + /** - * parseConnectionString produces a knex connection config object representing - * a database connection string. + * Produces a knex connection config object representing a database connection + * string. */ parseConnectionString( connectionString: string, client?: string, ): Knex.StaticConnectionConfig; + /** - * ensureDatabaseExists performs a side-effect to ensure database names passed in are - * present. + * Performs a side-effect to ensure database names passed in are present. * * Calling this function on databases which already exist should do nothing. * Missing databases should be created if needed. @@ -69,8 +71,7 @@ export interface DatabaseConnector { ): Promise; /** - * ensureSchemaExists performs a side-effect to ensure schema names passed in are - * present. + * Performs a side-effect to ensure schema names passed in are present. * * Calling this function on schemas which already exist should do nothing. * Missing schemas should be created if needed. @@ -80,5 +81,20 @@ export interface DatabaseConnector { ...schemas: Array ): Promise; + /** + * Deletes databases. + */ dropDatabase?(dbConfig: Config, ...databases: Array): Promise; } + +export interface Connector { + getClient( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): Promise; + + dropDatabase(...databaseNames: string[]): Promise; +} diff --git a/packages/backend-common/src/deprecated/index.ts b/packages/backend-common/src/deprecated/index.ts new file mode 100644 index 0000000000..d9ca795c3a --- /dev/null +++ b/packages/backend-common/src/deprecated/index.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './scm'; + +import { + isDatabaseConflictError as _isDatabaseConflictError, + resolvePackagePath as _resolvePackagePath, + resolveSafeChildPath as _resolveSafeChildPath, + isChildPath as _isChildPath, +} from '@backstage/backend-plugin-api'; + +/** + * @public + * @deprecated This function is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + * Please use the `isDatabaseConflictError` function from the `@backstage/backend-plugin-api` package instead. + */ +export const isDatabaseConflictError = _isDatabaseConflictError; + +/** + * @public + * @deprecated This function is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + * Please use the `resolvePackagePath` function from the `@backstage/backend-plugin-api` package instead. + */ +export const resolvePackagePath = _resolvePackagePath; + +/** + * @public + * @deprecated This function is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + * Please use the `resolveSafeChildPath` function from the `@backstage/backend-plugin-api` package instead. + */ +export const resolveSafeChildPath = _resolveSafeChildPath; + +/** + * @public + * @deprecated This function is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + * Please use the `isChildPath` function from the `@backstage/cli-common` package instead. + */ +export const isChildPath = _isChildPath; diff --git a/packages/backend-common/src/scm/git.test.ts b/packages/backend-common/src/deprecated/scm/git.test.ts similarity index 100% rename from packages/backend-common/src/scm/git.test.ts rename to packages/backend-common/src/deprecated/scm/git.test.ts diff --git a/packages/backend-common/src/deprecated/scm/git.ts b/packages/backend-common/src/deprecated/scm/git.ts new file mode 100644 index 0000000000..1a182e6f4d --- /dev/null +++ b/packages/backend-common/src/deprecated/scm/git.ts @@ -0,0 +1,357 @@ +/* + * 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 git, { + ProgressCallback, + MergeResult, + ReadCommitResult, + AuthCallback, +} from 'isomorphic-git'; +import http from 'isomorphic-git/http/node'; +import fs from 'fs-extra'; +import { LoggerService } from '@backstage/backend-plugin-api'; + +function isAuthCallbackOptions( + options: StaticAuthOptions | AuthCallbackOptions, +): options is AuthCallbackOptions { + return 'onAuth' in options; +} + +/** + * Configure static credential for authentication + * @public + * @deprecated This type is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + */ +export type StaticAuthOptions = { + username?: string; + password?: string; + token?: string; + logger?: LoggerService; +}; + +/** + * Configure an authentication callback that can provide credentials on demand + * @public + * @deprecated This type is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + */ +export type AuthCallbackOptions = { + onAuth: AuthCallback; + logger?: LoggerService; +}; + +/* +provider username password +Azure 'notempty' token +Bitbucket Cloud 'x-token-auth' token +Bitbucket Server username password or token +GitHub 'x-access-token' token +GitLab 'oauth2' token + +From : https://isomorphic-git.org/docs/en/onAuth with fix for GitHub + +Or token provided as `token` for Bearer auth header +instead of Basic Auth (e.g., Bitbucket Server). +*/ + +/** + * A convenience wrapper around the `isomorphic-git` library. + * @public + * @deprecated This class is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + */ + +export class Git { + private readonly headers: { + [x: string]: string; + }; + + private constructor( + private readonly config: { + onAuth: AuthCallback; + token?: string; + logger?: LoggerService; + }, + ) { + this.onAuth = config.onAuth; + + this.headers = { + 'user-agent': 'git/@isomorphic-git', + ...(config.token ? { Authorization: `Bearer ${config.token}` } : {}), + }; + } + + async add(options: { dir: string; filepath: string }): Promise { + const { dir, filepath } = options; + this.config.logger?.info(`Adding file {dir=${dir},filepath=${filepath}}`); + + return git.add({ fs, dir, filepath }); + } + + async addRemote(options: { + dir: string; + remote: string; + url: string; + force?: boolean; + }): Promise { + const { dir, url, remote, force } = options; + this.config.logger?.info( + `Creating new remote {dir=${dir},remote=${remote},url=${url}}`, + ); + return git.addRemote({ fs, dir, remote, url, force }); + } + + async deleteRemote(options: { dir: string; remote: string }): Promise { + const { dir, remote } = options; + this.config.logger?.info(`Deleting remote {dir=${dir},remote=${remote}}`); + return git.deleteRemote({ fs, dir, remote }); + } + + async checkout(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; + this.config.logger?.info(`Checking out branch {dir=${dir},ref=${ref}}`); + + return git.checkout({ fs, dir, ref }); + } + + async branch(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; + this.config.logger?.info(`Creating branch {dir=${dir},ref=${ref}`); + + return git.branch({ fs, dir, ref }); + } + + async commit(options: { + dir: string; + message: string; + author: { name: string; email: string }; + committer: { name: string; email: string }; + }): Promise { + const { dir, message, author, committer } = options; + this.config.logger?.info( + `Committing file to repo {dir=${dir},message=${message}}`, + ); + return git.commit({ fs, dir, message, author, committer }); + } + + /** https://isomorphic-git.org/docs/en/clone */ + async clone(options: { + url: string; + dir: string; + ref?: string; + depth?: number; + noCheckout?: boolean; + }): Promise { + const { url, dir, ref, depth, noCheckout } = options; + this.config.logger?.info(`Cloning repo {dir=${dir},url=${url}}`); + + try { + return await git.clone({ + fs, + http, + url, + dir, + ref, + singleBranch: true, + depth: depth ?? 1, + noCheckout, + onProgress: this.onProgressHandler(), + headers: this.headers, + onAuth: this.onAuth, + }); + } catch (ex) { + this.config.logger?.error(`Failed to clone repo {dir=${dir},url=${url}}`); + if (ex.data) { + throw new Error(`${ex.message} {data=${JSON.stringify(ex.data)}}`); + } + throw ex; + } + } + + /** https://isomorphic-git.org/docs/en/currentBranch */ + async currentBranch(options: { + dir: string; + fullName?: boolean; + }): Promise { + const { dir, fullName = false } = options; + return git.currentBranch({ fs, dir, fullname: fullName }) as Promise< + string | undefined + >; + } + + /** https://isomorphic-git.org/docs/en/fetch */ + async fetch(options: { + dir: string; + remote?: string; + tags?: boolean; + }): Promise { + const { dir, remote = 'origin', tags = false } = options; + this.config.logger?.info( + `Fetching remote=${remote} for repository {dir=${dir}}`, + ); + + try { + await git.fetch({ + fs, + http, + dir, + remote, + tags, + onProgress: this.onProgressHandler(), + headers: this.headers, + onAuth: this.onAuth, + }); + } catch (ex) { + this.config.logger?.error( + `Failed to fetch repo {dir=${dir},remote=${remote}}`, + ); + if (ex.data) { + throw new Error(`${ex.message} {data=${JSON.stringify(ex.data)}}`); + } + throw ex; + } + } + + async init(options: { dir: string; defaultBranch?: string }): Promise { + const { dir, defaultBranch = 'master' } = options; + this.config.logger?.info(`Init git repository {dir=${dir}}`); + + return git.init({ + fs, + dir, + defaultBranch, + }); + } + + /** https://isomorphic-git.org/docs/en/merge */ + async merge(options: { + dir: string; + theirs: string; + ours?: string; + author: { name: string; email: string }; + committer: { name: string; email: string }; + }): Promise { + const { dir, theirs, ours, author, committer } = options; + this.config.logger?.info( + `Merging branch '${theirs}' into '${ours}' for repository {dir=${dir}}`, + ); + + // If ours is undefined, current branch is used. + return git.merge({ + fs, + dir, + ours, + theirs, + author, + committer, + }); + } + + async push(options: { + dir: string; + remote: string; + remoteRef?: string; + force?: boolean; + }) { + const { dir, remote, remoteRef, force } = options; + this.config.logger?.info( + `Pushing directory to remote {dir=${dir},remote=${remote}}`, + ); + try { + return await git.push({ + fs, + dir, + http, + onProgress: this.onProgressHandler(), + remoteRef, + force, + headers: this.headers, + remote, + onAuth: this.onAuth, + }); + } catch (ex) { + this.config.logger?.error( + `Failed to push to repo {dir=${dir}, remote=${remote}}`, + ); + if (ex.data) { + throw new Error(`${ex.message} {data=${JSON.stringify(ex.data)}}`); + } + throw ex; + } + } + + /** https://isomorphic-git.org/docs/en/readCommit */ + async readCommit(options: { + dir: string; + sha: string; + }): Promise { + const { dir, sha } = options; + return git.readCommit({ fs, dir, oid: sha }); + } + + /** https://isomorphic-git.org/docs/en/remove */ + async remove(options: { dir: string; filepath: string }): Promise { + const { dir, filepath } = options; + this.config.logger?.info( + `Removing file from git index {dir=${dir},filepath=${filepath}}`, + ); + return git.remove({ fs, dir, filepath }); + } + + /** https://isomorphic-git.org/docs/en/resolveRef */ + async resolveRef(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; + return git.resolveRef({ fs, dir, ref }); + } + + /** https://isomorphic-git.org/docs/en/log */ + async log(options: { + dir: string; + ref?: string; + }): Promise { + const { dir, ref } = options; + return git.log({ + fs, + dir, + ref: ref ?? 'HEAD', + }); + } + + private onAuth: AuthCallback; + + private onProgressHandler = (): ProgressCallback => { + let currentPhase = ''; + + return event => { + if (currentPhase !== event.phase) { + currentPhase = event.phase; + this.config.logger?.info(event.phase); + } + const total = event.total + ? `${Math.round((event.loaded / event.total) * 100)}%` + : event.loaded; + this.config.logger?.debug(`status={${event.phase},total={${total}}}`); + }; + }; + + static fromAuth = (options: StaticAuthOptions | AuthCallbackOptions) => { + if (isAuthCallbackOptions(options)) { + const { onAuth, logger } = options; + return new Git({ onAuth, logger }); + } + + const { username, password, token, logger } = options; + return new Git({ onAuth: () => ({ username, password }), token, logger }); + }; +} diff --git a/packages/backend-common/src/scm/index.ts b/packages/backend-common/src/deprecated/scm/index.ts similarity index 100% rename from packages/backend-common/src/scm/index.ts rename to packages/backend-common/src/deprecated/scm/index.ts diff --git a/packages/backend-common/src/discovery/HostDiscovery.ts b/packages/backend-common/src/discovery/HostDiscovery.ts index 38ac975747..77810b7f6d 100644 --- a/packages/backend-common/src/discovery/HostDiscovery.ts +++ b/packages/backend-common/src/discovery/HostDiscovery.ts @@ -15,8 +15,13 @@ */ import { HostDiscovery as _HostDiscovery } from '@backstage/backend-app-api'; +import { DiscoveryService } from '@backstage/backend-plugin-api'; -export type { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api'; +/** + * @public + * @deprecated Use `DiscoveryService` from `@backstage/backend-plugin-api` instead + */ +export type PluginEndpointDiscovery = DiscoveryService; /** * HostDiscovery is a basic PluginEndpointDiscovery implementation @@ -27,6 +32,7 @@ export type { DiscoveryService as PluginEndpointDiscovery } from '@backstage/bac * resolved to the same host, so there won't be any balancing of internal traffic. * * @public + * @deprecated Please import from `@backstage/backend-defaults/discovery` instead. */ export const HostDiscovery = _HostDiscovery; @@ -39,6 +45,6 @@ export const HostDiscovery = _HostDiscovery; * resolved to the same host, so there won't be any balancing of internal traffic. * * @public - * @deprecated Use {@link HostDiscovery} instead + * @deprecated Use `HostDiscovery` from `@backstage/backend-defaults/discovery` instead */ export const SingleHostDiscovery = _HostDiscovery; diff --git a/packages/backend-common/src/discovery/index.ts b/packages/backend-common/src/discovery/index.ts index bad721d4da..827fd059ad 100644 --- a/packages/backend-common/src/discovery/index.ts +++ b/packages/backend-common/src/discovery/index.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export { HostDiscovery, SingleHostDiscovery, diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index 4b1314b7d2..87bfa245f6 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -25,14 +25,13 @@ export type { LegacyCreateRouter } from './legacy'; export * from './auth'; export * from './cache'; export { loadBackendConfig } from './config'; +export * from './deprecated'; export * from './database'; export * from './discovery'; export * from './hot'; export * from './logging'; export * from './middleware'; -export * from './paths'; export * from './reading'; -export * from './scm'; export * from './service'; export * from './tokens'; export * from './util'; diff --git a/packages/backend-common/src/legacy.test.ts b/packages/backend-common/src/legacy.test.ts new file mode 100644 index 0000000000..1ddebce5c4 --- /dev/null +++ b/packages/backend-common/src/legacy.test.ts @@ -0,0 +1,118 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { EventEmitter } from 'events'; +import { Router } from 'express'; +import { createLegacyAuthAdapters } from './auth'; +import { legacyPlugin } from './legacy'; +import { + authServiceFactory, + tokenManagerServiceFactory, +} from '@backstage/backend-app-api'; + +describe('legacyPlugin', () => { + it('can auth across the new and old systems', async () => { + const emitter = new EventEmitter(); + + const done = new Promise(resolve => { + emitter.once('done', () => { + emitter.once('done', resolve); + }); + }); + + await startTestBackend({ + features: [ + authServiceFactory, + tokenManagerServiceFactory, + mockServices.rootConfig.factory({ + data: { + backend: { + auth: { + keys: [ + { + secret: 'test', + }, + ], + }, + }, + }, + }), + createBackendPlugin({ + pluginId: 'new', + register(reg) { + reg.registerInit({ + deps: { + auth: coreServices.auth, + discovery: coreServices.discovery, + }, + async init({ auth }) { + emitter.once('legacy-token', async otherToken => { + const credentials = await auth.authenticate(otherToken); + expect(credentials.principal).toEqual({ + type: 'service', + subject: 'external:backstage-plugin', + }); + emitter.emit('done'); + }); + + const { token } = await auth.getPluginRequestToken({ + onBehalfOf: await auth.getOwnServiceCredentials(), + targetPluginId: 'old', + }); + emitter.emit('new-token', token); + }, + }); + }, + }), + legacyPlugin( + 'old', + Promise.resolve({ + async default({ tokenManager, identity, discovery }) { + const { auth } = createLegacyAuthAdapters({ + tokenManager, + identity, + discovery, + auth: undefined as any as typeof coreServices.auth.T, + httpAuth: undefined as any as typeof coreServices.httpAuth.T, + }); + + emitter.once('new-token', async otherToken => { + const credentials = await auth.authenticate(otherToken); + expect(credentials.principal).toEqual({ + type: 'service', + subject: 'external:backstage-plugin', + }); + emitter.emit('done'); + }); + + const { token } = await tokenManager.getToken(); + emitter.emit('legacy-token', token); + + return Router(); + }, + }), + ), + ], + }); + + await done; + }); +}); diff --git a/packages/backend-common/src/legacy.ts b/packages/backend-common/src/legacy.ts index df1030e6b6..6aa991489c 100644 --- a/packages/backend-common/src/legacy.ts +++ b/packages/backend-common/src/legacy.ts @@ -15,6 +15,7 @@ */ import { + AuthService, coreServices, createBackendPlugin, ServiceRef, @@ -22,6 +23,7 @@ import { import { RequestHandler } from 'express'; import { cacheToPluginCacheManager } from './cache'; import { loggerToWinstonLogger } from './logging'; +import { TokenManager } from './tokens'; /** * @public @@ -38,6 +40,31 @@ type TransformedEnv< : TEnv[key]; }; +// Since the plugin will be using the new system our callers will expect us to support the +// new plugin tokens, which we'll also be signaling by supporting the JWKS endpoint through +// the http router. +// This makes sure that we accept the new plugin tokens as valid tokens, but otherwise fall +// back to whatever the token manager is doing. +function wrapTokenManager(tokenManager: TokenManager, auth: AuthService) { + return { + async getToken() { + return tokenManager.getToken(); + }, + async authenticate(token) { + if (token) { + // Unless it's a valid service token, we'll let the token manager do + // validation. We'll throw if we for example receive an invalid user + // token here, but that's what the token manager does too. + const credentials = await auth.authenticate(token); + if (auth.isPrincipal(credentials, 'service')) { + return; + } + } + await tokenManager.authenticate(token); + }, + } satisfies TokenManager; +} + /** * Creates a new custom plugin compatibility wrapper. * @@ -64,8 +91,12 @@ export function makeLegacyPlugin< pluginId: name, register(env) { env.registerInit({ - deps: { ...envMapping, _router: coreServices.httpRouter }, - async init({ _router, ...envDeps }) { + deps: { + ...envMapping, + _router: coreServices.httpRouter, + _auth: coreServices.auth, + }, + async init({ _router, _auth, ...envDeps }) { const { default: createRouter } = await createRouterImport; const pluginEnv = Object.fromEntries( Object.entries(envDeps).map(([key, dep]) => { @@ -73,6 +104,9 @@ export function makeLegacyPlugin< if (transform) { return [key, transform(dep)]; } + if (key === 'tokenManager') { + return [key, wrapTokenManager(dep as TokenManager, _auth)]; + } return [key, dep]; }), ); diff --git a/packages/backend-common/src/logging/createRootLogger.ts b/packages/backend-common/src/logging/createRootLogger.ts index f9a3ed4ba0..16554750ef 100644 --- a/packages/backend-common/src/logging/createRootLogger.ts +++ b/packages/backend-common/src/logging/createRootLogger.ts @@ -59,6 +59,8 @@ const colorizer = format.colorize(); * Creates a pretty printed winston log formatter. * * @public + * @deprecated As we are going to deprecate the legacy backend, this formatter utility will be removed in the future. + * If you need to format logs in the new system, please use the `WinstonLogger.colorFormat()` from `@backstage/backend-app-api` instead. */ export const coloredFormat = format.combine( format.timestamp(), @@ -96,6 +98,9 @@ export const coloredFormat = format.combine( * instances passed to plugins etc, in a given backend. * * @public + * @deprecated As we are going to deprecate the legacy backend, this function will be removed in the future. + * If you need to create the root logger in the new system, please check out this documentation: + * https://backstage.io/docs/backend-system/core-services/logger */ export function createRootLogger( options: winston.LoggerOptions = {}, diff --git a/packages/backend-common/src/logging/globalLoggers.ts b/packages/backend-common/src/logging/globalLoggers.ts index 8b473db211..cbd5279d29 100644 --- a/packages/backend-common/src/logging/globalLoggers.ts +++ b/packages/backend-common/src/logging/globalLoggers.ts @@ -21,6 +21,8 @@ import { createRootLogger } from './createRootLogger'; * A logger that just throws away all messages. * * @public + * @deprecated As we are going to deprecate the legacy backend, this function will be removed in the future. + * If you need to mock the root logger in the new system, please use `mockServices.logger.mock()` from `@backstage/test-utils` instead. */ export function getVoidLogger(): winston.Logger { return winston.createLogger({ @@ -34,6 +36,9 @@ let rootLogger: winston.Logger; * Gets the current root logger. * * @public + * @deprecated As we are going to deprecate the legacy backend, this function will be removed in the future. + * If you need to get the root logger in the new system, please check out this documentation: + * https://backstage.io/docs/backend-system/core-services/logger */ export function getRootLogger(): winston.Logger { if (!rootLogger) { @@ -55,6 +60,9 @@ export function getRootLogger(): winston.Logger { * behavior, you would instead call {@link createRootLogger}. * * @public + * @deprecated As we are going to deprecate the legacy backend, this function will be removed in the future. + * If you need to set the root logger in the new system, please check out this documentation: + * https://backstage.io/docs/backend-system/core-services/logger */ export function setRootLogger(newLogger: winston.Logger) { rootLogger = newLogger; diff --git a/packages/backend-common/src/middleware/errorHandler.ts b/packages/backend-common/src/middleware/errorHandler.ts index 99ede75ab0..110734b0a2 100644 --- a/packages/backend-common/src/middleware/errorHandler.ts +++ b/packages/backend-common/src/middleware/errorHandler.ts @@ -61,6 +61,7 @@ export type ErrorHandlerOptions = { * * @public * @returns An Express error request handler + * @deprecated Use {@link @backstage/backend-app-api#MiddlewareFactory.create.error} instead */ export function errorHandler( options: ErrorHandlerOptions = {}, diff --git a/packages/backend-common/src/middleware/requestLoggingHandler.ts b/packages/backend-common/src/middleware/requestLoggingHandler.ts index a03e3c31f6..81dfa1d345 100644 --- a/packages/backend-common/src/middleware/requestLoggingHandler.ts +++ b/packages/backend-common/src/middleware/requestLoggingHandler.ts @@ -26,6 +26,7 @@ import { ConfigReader } from '@backstage/config'; * @public * @param logger - An optional logger to use. If not specified, the root logger will be used. * @returns An Express request handler + * @deprecated @deprecated Use {@link @backstage/backend-app-api#MiddlewareFactory.create.logging} instead */ export function requestLoggingHandler(logger?: LoggerService): RequestHandler { return MiddlewareFactory.create({ diff --git a/packages/backend-common/src/reading/AwsCodeCommitUrlReader.test.ts b/packages/backend-common/src/reading/AwsCodeCommitUrlReader.test.ts index 44d785d9c4..6263d073fc 100644 --- a/packages/backend-common/src/reading/AwsCodeCommitUrlReader.test.ts +++ b/packages/backend-common/src/reading/AwsCodeCommitUrlReader.test.ts @@ -16,7 +16,6 @@ import { ConfigReader } from '@backstage/config'; import { JsonObject } from '@backstage/types'; -import { getVoidLogger } from '../logging'; import { DefaultReadTreeResponseFactory } from './tree'; import { AwsCodeCommitUrlReader, parseUrl } from './AwsCodeCommitUrlReader'; import { UrlReaderPredicateTuple } from './types'; @@ -34,6 +33,7 @@ import { AwsCodeCommitIntegration, readAwsCodeCommitIntegrationConfig, } from '@backstage/integration'; +import { mockServices } from '@backstage/backend-test-utils'; const AMAZON_AWS_CODECOMMIT_HOST = 'console.aws.amazon.com'; @@ -202,7 +202,7 @@ describe('AwsCodeCommitUrlReader', () => { const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { return AwsCodeCommitUrlReader.factory({ config: new ConfigReader(config), - logger: getVoidLogger(), + logger: mockServices.logger.mock(), treeResponseFactory, }); }; diff --git a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts index e3247f190b..15f46199da 100644 --- a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts +++ b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts @@ -16,7 +16,6 @@ import { ConfigReader } from '@backstage/config'; import { JsonObject } from '@backstage/types'; -import { getVoidLogger } from '../logging'; import { DefaultReadTreeResponseFactory } from './tree'; import { DEFAULT_REGION, AwsS3UrlReader, parseUrl } from './AwsS3UrlReader'; import { @@ -37,6 +36,7 @@ import { } from '@aws-sdk/client-s3'; import { sdkStreamMixin } from '@aws-sdk/util-stream-node'; import fs from 'fs'; +import { mockServices } from '@backstage/backend-test-utils'; const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), @@ -166,7 +166,7 @@ describe('AwsS3UrlReader', () => { const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { return AwsS3UrlReader.factory({ config: new ConfigReader(config), - logger: getVoidLogger(), + logger: mockServices.logger.mock(), treeResponseFactory, }); }; diff --git a/packages/backend-common/src/reading/AzureUrlReader.test.ts b/packages/backend-common/src/reading/AzureUrlReader.test.ts index 2b4bc84be7..ce2385507b 100644 --- a/packages/backend-common/src/reading/AzureUrlReader.test.ts +++ b/packages/backend-common/src/reading/AzureUrlReader.test.ts @@ -25,6 +25,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, + mockServices, setupRequestMockHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; @@ -32,7 +33,6 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import path from 'path'; import { NotModifiedError } from '@backstage/errors'; -import { getVoidLogger } from '../logging'; import { AzureUrlReader } from './AzureUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; @@ -42,7 +42,7 @@ type AzureIntegrationConfigLike = Partial< credentials?: Partial[]; }; -const logger = getVoidLogger(); +const logger = mockServices.logger.mock(); const mockDir = createMockDirectory({ mockOsTmpDir: true }); diff --git a/packages/backend-common/src/reading/BitbucketUrlReader.test.ts b/packages/backend-common/src/reading/BitbucketUrlReader.test.ts index 4258ac9d5b..edd8d6d3fc 100644 --- a/packages/backend-common/src/reading/BitbucketUrlReader.test.ts +++ b/packages/backend-common/src/reading/BitbucketUrlReader.test.ts @@ -21,6 +21,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, + mockServices, setupRequestMockHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; @@ -30,10 +31,9 @@ import path from 'path'; import { NotModifiedError } from '@backstage/errors'; import { BitbucketUrlReader } from './BitbucketUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; -import { getVoidLogger } from '../logging'; import getRawBody from 'raw-body'; -const logger = getVoidLogger(); +const logger = mockServices.logger.mock(); describe('BitbucketUrlReader.factory', () => { it('only apply integration configs not inherited from bitbucketCloud or bitbucketServer', () => { diff --git a/packages/backend-common/src/reading/FetchUrlReader.test.ts b/packages/backend-common/src/reading/FetchUrlReader.test.ts index 7b5e4ebc05..38936806c6 100644 --- a/packages/backend-common/src/reading/FetchUrlReader.test.ts +++ b/packages/backend-common/src/reading/FetchUrlReader.test.ts @@ -16,10 +16,12 @@ import { ConfigReader } from '@backstage/config'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { getVoidLogger } from '../logging'; import { FetchUrlReader } from './FetchUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; @@ -77,7 +79,7 @@ describe('FetchUrlReader', () => { worker.use( rest.get('https://backstage.io/error', (_req, res, ctx) => { - return res(ctx.status(500), ctx.body('An internal error occured')); + return res(ctx.status(500), ctx.body('An internal error occurred')); }), ); }); @@ -105,7 +107,7 @@ describe('FetchUrlReader', () => { }, }, }), - logger: getVoidLogger(), + logger: mockServices.logger.mock(), treeResponseFactory: DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }), @@ -155,7 +157,7 @@ describe('FetchUrlReader', () => { }, }, }), - logger: getVoidLogger(), + logger: mockServices.logger.mock(), treeResponseFactory: DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }), diff --git a/packages/backend-common/src/reading/GerritUrlReader.test.ts b/packages/backend-common/src/reading/GerritUrlReader.test.ts index 66943cac51..ca4a2707f3 100644 --- a/packages/backend-common/src/reading/GerritUrlReader.test.ts +++ b/packages/backend-common/src/reading/GerritUrlReader.test.ts @@ -16,6 +16,7 @@ import { createMockDirectory, + mockServices, setupRequestMockHandlers, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; @@ -29,7 +30,6 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import fs from 'fs-extra'; import path from 'path'; -import { getVoidLogger } from '../logging'; import { UrlReaderPredicateTuple } from './types'; import { DefaultReadTreeResponseFactory } from './tree'; import { @@ -47,7 +47,7 @@ const treeResponseFactory = DefaultReadTreeResponseFactory.create({ }); const cloneMock = jest.fn(() => Promise.resolve()); -jest.mock('../scm', () => ({ +jest.mock('./git', () => ({ Git: { fromAuth: () => ({ clone: cloneMock, @@ -86,7 +86,7 @@ const gerritProcessorWithGitiles = new GerritUrlReader( const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { return GerritUrlReader.factory({ config: new ConfigReader(config), - logger: getVoidLogger(), + logger: mockServices.logger.mock(), treeResponseFactory, }); }; diff --git a/packages/backend-common/src/reading/GerritUrlReader.ts b/packages/backend-common/src/reading/GerritUrlReader.ts index 76de711dec..52a541382b 100644 --- a/packages/backend-common/src/reading/GerritUrlReader.ts +++ b/packages/backend-common/src/reading/GerritUrlReader.ts @@ -14,7 +14,15 @@ * limitations under the License. */ -import { NotFoundError, NotModifiedError } from '@backstage/errors'; +import { Base64Decode } from 'base64-stream'; +import concatStream from 'concat-stream'; +import fs from 'fs-extra'; +import fetch, { Response } from 'node-fetch'; +import os from 'os'; +import { join as joinPath } from 'path'; +import { Readable, pipeline as pipelineCb } from 'stream'; +import tar from 'tar'; +import { promisify } from 'util'; import { GerritIntegration, ScmIntegrations, @@ -26,16 +34,7 @@ import { parseGerritGitilesUrl, parseGerritJsonResponse, } from '@backstage/integration'; -import { Base64Decode } from 'base64-stream'; -import concatStream from 'concat-stream'; -import fs from 'fs-extra'; -import fetch, { Response } from 'node-fetch'; -import os from 'os'; -import { join as joinPath } from 'path'; -import { Readable, pipeline as pipelineCb } from 'stream'; -import tar from 'tar'; -import { promisify } from 'util'; -import { Git } from '../scm'; +import { NotFoundError, NotModifiedError } from '@backstage/errors'; import { ReadTreeOptions, ReadTreeResponse, @@ -46,6 +45,7 @@ import { SearchResponse, UrlReader, } from './types'; +import { Git } from './git'; const pipeline = promisify(pipelineCb); diff --git a/packages/backend-common/src/reading/GiteaUrlReader.test.ts b/packages/backend-common/src/reading/GiteaUrlReader.test.ts index a941d2e5aa..0b5983eefd 100644 --- a/packages/backend-common/src/reading/GiteaUrlReader.test.ts +++ b/packages/backend-common/src/reading/GiteaUrlReader.test.ts @@ -14,13 +14,15 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { GiteaIntegration, readGiteaConfig } from '@backstage/integration'; import { JsonObject } from '@backstage/types'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { getVoidLogger } from '../logging'; import { UrlReaderPredicateTuple } from './types'; import { DefaultReadTreeResponseFactory } from './tree'; import getRawBody from 'raw-body'; @@ -33,7 +35,7 @@ const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); -jest.mock('../scm', () => ({ +jest.mock('./git', () => ({ Git: { fromAuth: () => ({ clone: jest.fn(() => Promise.resolve({})), @@ -55,7 +57,7 @@ const giteaProcessor = new GiteaUrlReader( const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { return GiteaUrlReader.factory({ config: new ConfigReader(config), - logger: getVoidLogger(), + logger: mockServices.logger.mock(), treeResponseFactory, }); }; diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index 3c065e8b81..46276fcdda 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -17,13 +17,13 @@ import { ConfigReader } from '@backstage/config'; import { createMockDirectory, + mockServices, setupRequestMockHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import path from 'path'; -import { getVoidLogger } from '../logging'; import { GitlabUrlReader } from './GitlabUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; import { NotModifiedError, NotFoundError } from '@backstage/errors'; @@ -32,7 +32,7 @@ import { readGitLabIntegrationConfig, } from '@backstage/integration'; -const logger = getVoidLogger(); +const logger = mockServices.logger.mock(); const mockDir = createMockDirectory({ mockOsTmpDir: true }); diff --git a/packages/backend-common/src/reading/GoogleGcsUrlReader.test.ts b/packages/backend-common/src/reading/GoogleGcsUrlReader.test.ts index 25bce25686..bc31818d23 100644 --- a/packages/backend-common/src/reading/GoogleGcsUrlReader.test.ts +++ b/packages/backend-common/src/reading/GoogleGcsUrlReader.test.ts @@ -16,11 +16,11 @@ import { ConfigReader } from '@backstage/config'; import { JsonObject } from '@backstage/types'; -import { getVoidLogger } from '../logging'; import { DefaultReadTreeResponseFactory } from './tree'; import { GoogleGcsUrlReader } from './GoogleGcsUrlReader'; import { UrlReaderPredicateTuple } from './types'; import packageinfo from '../../package.json'; +import { mockServices } from '@backstage/backend-test-utils'; const bucketGetFilesMock = jest.fn(); jest.mock('@google-cloud/storage', () => { @@ -44,7 +44,7 @@ describe('GcsUrlReader', () => { const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { return GoogleGcsUrlReader.factory({ config: new ConfigReader(config), - logger: getVoidLogger(), + logger: mockServices.logger.mock(), treeResponseFactory: DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }), diff --git a/packages/backend-common/src/reading/HarnessUrlReader.test.ts b/packages/backend-common/src/reading/HarnessUrlReader.test.ts new file mode 100644 index 0000000000..7cc37add3b --- /dev/null +++ b/packages/backend-common/src/reading/HarnessUrlReader.test.ts @@ -0,0 +1,187 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + mockServices, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { HarnessIntegration, readHarnessConfig } from '@backstage/integration'; +import { JsonObject } from '@backstage/types'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { UrlReaderPredicateTuple } from './types'; +import { DefaultReadTreeResponseFactory } from './tree'; +import getRawBody from 'raw-body'; +import { HarnessUrlReader } from './HarnessUrlReader'; + +const treeResponseFactory = DefaultReadTreeResponseFactory.create({ + config: new ConfigReader({}), +}); + +jest.mock('./git', () => ({ + Git: { + fromAuth: () => ({ + clone: jest.fn(() => Promise.resolve({})), + }), + }, +})); + +const harnessProcessor = new HarnessUrlReader( + new HarnessIntegration( + readHarnessConfig( + new ConfigReader({ + host: 'app.harness.io', + token: 'p', + }), + ), + ), +); + +const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { + return HarnessUrlReader.factory({ + config: new ConfigReader(config), + logger: mockServices.logger.mock(), + treeResponseFactory, + }); +}; +const responseBuffer = Buffer.from('Apache License'); +const harnessApiResponse = (content: any) => { + return content; +}; + +const handlers = [ + rest.get( + 'https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/:path+/raw/all-apis.yaml', + (_req, res, ctx) => { + return res(ctx.status(500), ctx.json({ message: 'Error!!!' })); + }, + ), + rest.get( + 'https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/:path+/raw/404error.yaml', + (_req, res, ctx) => { + return res(ctx.status(404), ctx.json({ message: 'File not found.' })); + }, + ), + rest.get( + 'https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/:path+/raw/stream.TXT', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.body(harnessApiResponse(responseBuffer.toString())), + ); + }, + ), + + rest.get( + 'https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/:path+/raw/buffer.TXT', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.body(harnessApiResponse(responseBuffer.toString())), + ); + }, + ), +]; + +describe('HarnessUrlReader', () => { + const worker = setupServer(...handlers); + setupRequestMockHandlers(worker); + beforeAll(() => worker.listen({ onUnhandledRequest: 'bypass' })); + afterAll(() => { + jest.clearAllMocks(); + }); + + describe('reader factory', () => { + it('creates a reader.', () => { + const readers = createReader({ + integrations: { + harness: [{ host: 'app.harness.io' }], + }, + }); + expect(readers).toHaveLength(1); + }); + + it('should not create a default entry.', () => { + const readers = createReader({ + integrations: {}, + }); + expect(readers).toHaveLength(0); + }); + }); + + describe('predicates', () => { + it('returns true for the configured host', () => { + const readers = createReader({ + integrations: { + harness: [{ host: 'app.harness.io' }], + }, + }); + const predicate = readers[0].predicate; + + expect(predicate(new URL('https://app.harness.io/path'))).toBe(true); + }); + + it('returns false for a different host.', () => { + const readers = createReader({ + integrations: { + harness: [{ host: 'app.harness.io' }], + }, + }); + const predicate = readers[0].predicate; + + expect(predicate(new URL('https://github.com/path'))).toBe(false); + }); + }); + + describe('readUrl part 1', () => { + it('should be able to read file contents as buffer', async () => { + const result = await harnessProcessor.readUrl( + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/buffer.TXT', + ); + const buffer = await result.buffer(); + expect(buffer.toString()).toBe(responseBuffer.toString()); + }); + + it('should be able to read file contents as stream', async () => { + const result = await harnessProcessor.readUrl( + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/stream.TXT', + ); + const fromStream = await getRawBody(result.stream!()); + expect(fromStream.toString()).toBe(responseBuffer.toString()); + }); + + it('should raise NotFoundError on 404.', async () => { + await expect( + harnessProcessor.readUrl( + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/404error.yaml', + ), + ).rejects.toThrow( + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/404error.yaml x https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/+/raw/404error.yaml?routingId=accountId&git_ref=refMain, 404 Not Found', + ); + }); + + it('should throw an error on non 404 errors.', async () => { + await expect( + harnessProcessor.readUrl( + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/all-apis.yaml', + ), + ).rejects.toThrow( + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/all-apis.yaml x https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/+/raw/all-apis.yaml?routingId=accountId&git_ref=refMain, 500 Internal Server Error', + ); + }); + }); +}); diff --git a/packages/backend-common/src/reading/HarnessUrlReader.ts b/packages/backend-common/src/reading/HarnessUrlReader.ts new file mode 100644 index 0000000000..09291c5176 --- /dev/null +++ b/packages/backend-common/src/reading/HarnessUrlReader.ts @@ -0,0 +1,125 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { + getHarnessRequestOptions, + getHarnessFileContentsUrl, + HarnessIntegration, + ScmIntegrations, +} from '@backstage/integration'; +import { ReadUrlOptions, ReadUrlResponse } from './types'; +import { + ReaderFactory, + ReadTreeResponse, + SearchResponse, + UrlReader, +} from './types'; +import fetch, { Response } from 'node-fetch'; +import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; +import { + AuthenticationError, + NotFoundError, + NotModifiedError, +} from '@backstage/errors'; +import { Readable } from 'stream'; + +/** + * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for the Harness code v1 api. + * + * + * @public + */ +export class HarnessUrlReader implements UrlReader { + static factory: ReaderFactory = ({ config }) => { + return ScmIntegrations.fromConfig(config) + .harness.list() + .map(integration => { + const reader = new HarnessUrlReader(integration); + const predicate = (url: URL) => { + return url.host === integration.config.host; + }; + return { reader, predicate }; + }); + }; + + constructor(private readonly integration: HarnessIntegration) {} + + async read(url: string): Promise { + const response = await this.readUrl(url); + return response.buffer(); + } + + async readUrl( + url: string, + options?: ReadUrlOptions, + ): Promise { + let response: Response; + const blobUrl = getHarnessFileContentsUrl(this.integration.config, url); + + try { + response = await fetch(blobUrl, { + method: 'GET', + ...getHarnessRequestOptions(this.integration.config), + signal: options?.signal as any, + }); + } catch (e) { + throw new Error(`Unable to read ${blobUrl}, ${e}`); + } + + if (response.ok) { + // Harness Code returns the raw content object + const jsonResponse = { data: response.body }; + if (jsonResponse) { + return ReadUrlResponseFactory.fromReadable( + Readable.from(jsonResponse.data), + { + etag: response.headers.get('ETag') ?? undefined, + }, + ); + } + + throw new Error(`Unknown json: ${jsonResponse}`); + } + + const message = `${url} x ${blobUrl}, ${response.status} ${response.statusText}`; + if (response.status === 404) { + throw new NotFoundError(message); + } + + if (response.status === 304) { + throw new NotModifiedError(); + } + + if (response.status === 403) { + throw new AuthenticationError(); + } + + throw new Error(message); + } + + readTree(): Promise { + throw new Error('HarnessUrlReader readTree not implemented.'); + } + search(): Promise { + throw new Error('HarnessUrlReader search not implemented.'); + } + + toString() { + const { host } = this.integration.config; + return `harness{host=${host},authed=${Boolean( + this.integration.config.token || this.integration.config.apiKey, + )}}`; + } +} diff --git a/packages/backend-common/src/reading/UrlReaders.ts b/packages/backend-common/src/reading/UrlReaders.ts index e987eb9186..7aaaf120b4 100644 --- a/packages/backend-common/src/reading/UrlReaders.ts +++ b/packages/backend-common/src/reading/UrlReaders.ts @@ -31,6 +31,7 @@ import { GoogleGcsUrlReader } from './GoogleGcsUrlReader'; import { AwsS3UrlReader } from './AwsS3UrlReader'; import { GiteaUrlReader } from './GiteaUrlReader'; import { AwsCodeCommitUrlReader } from './AwsCodeCommitUrlReader'; +import { HarnessUrlReader } from './HarnessUrlReader'; /** * Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}. @@ -61,7 +62,6 @@ export class UrlReaders { const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config, }); - for (const factory of factories ?? []) { const tuples = factory({ config, logger: logger, treeResponseFactory }); @@ -94,6 +94,7 @@ export class UrlReaders { GiteaUrlReader.factory, GitlabUrlReader.factory, GoogleGcsUrlReader.factory, + HarnessUrlReader.factory, AwsS3UrlReader.factory, AwsCodeCommitUrlReader.factory, FetchUrlReader.factory, diff --git a/packages/backend-common/src/reading/git.ts b/packages/backend-common/src/reading/git.ts new file mode 100644 index 0000000000..119d4f64bd --- /dev/null +++ b/packages/backend-common/src/reading/git.ts @@ -0,0 +1,148 @@ +/* + * 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 fs from 'fs-extra'; +import isomorphicGit, { ProgressCallback, AuthCallback } from 'isomorphic-git'; +import http from 'isomorphic-git/http/node'; +import { LoggerService } from '@backstage/backend-plugin-api'; + +/** + * Configure static credential for authentication + * + * @public + */ +export type StaticAuthOptions = { + username?: string; + password?: string; + token?: string; + logger?: LoggerService; +}; + +/** + * Configure an authentication callback that can provide credentials on demand + * + * @public + */ +export type AuthCallbackOptions = { + onAuth: AuthCallback; + logger?: LoggerService; +}; + +function isAuthCallbackOptions( + options: StaticAuthOptions | AuthCallbackOptions, +): options is AuthCallbackOptions { + return 'onAuth' in options; +} + +/* +provider username password +Azure 'notempty' token +Bitbucket Cloud 'x-token-auth' token +Bitbucket Server username password or token +GitHub 'x-access-token' token +GitLab 'oauth2' token + +From : https://isomorphic-git.org/docs/en/onAuth with fix for GitHub + +Or token provided as `token` for Bearer auth header +instead of Basic Auth (e.g., Bitbucket Server). +*/ +/** + * A convenience wrapper around the `isomorphic-git` library. + * + * @public + */ +export class Git { + private readonly headers: { + [x: string]: string; + }; + + private constructor( + private readonly config: { + onAuth: AuthCallback; + token?: string; + logger?: LoggerService; + }, + ) { + this.onAuth = config.onAuth; + + this.headers = { + 'user-agent': 'git/@isomorphic-git', + ...(config.token ? { Authorization: `Bearer ${config.token}` } : {}), + }; + } + + /** https://isomorphic-git.org/docs/en/clone */ + async clone(options: { + url: string; + dir: string; + ref?: string; + depth?: number; + noCheckout?: boolean; + }): Promise { + const { url, dir, ref, depth, noCheckout } = options; + this.config.logger?.info(`Cloning repo {dir=${dir},url=${url}}`); + + try { + return await isomorphicGit.clone({ + fs, + http, + url, + dir, + ref, + singleBranch: true, + depth: depth ?? 1, + noCheckout, + onProgress: this.onProgressHandler(), + headers: this.headers, + onAuth: this.onAuth, + }); + } catch (ex) { + this.config.logger?.error(`Failed to clone repo {dir=${dir},url=${url}}`); + if (ex.data) { + throw new Error(`${ex.message} {data=${JSON.stringify(ex.data)}}`); + } + throw ex; + } + } + + private onAuth: AuthCallback; + + private onProgressHandler = (): ProgressCallback => { + let currentPhase = ''; + + return event => { + if (currentPhase !== event.phase) { + currentPhase = event.phase; + this.config.logger?.info(event.phase); + } + const total = event.total + ? `${Math.round((event.loaded / event.total) * 100)}%` + : event.loaded; + this.config.logger?.debug(`status={${event.phase},total={${total}}}`); + }; + }; + + static fromAuth = (options: StaticAuthOptions | AuthCallbackOptions) => { + if (isAuthCallbackOptions(options)) { + const { onAuth, logger } = options; + return new Git({ onAuth, logger }); + } + + const { username, password, token, logger } = options; + return new Git({ onAuth: () => ({ username, password }), token, logger }); + }; +} diff --git a/packages/backend-common/src/reading/index.ts b/packages/backend-common/src/reading/index.ts index 21e82da9b5..a99bb6dda1 100644 --- a/packages/backend-common/src/reading/index.ts +++ b/packages/backend-common/src/reading/index.ts @@ -22,6 +22,7 @@ export { GerritUrlReader } from './GerritUrlReader'; export { GithubUrlReader } from './GithubUrlReader'; export { GitlabUrlReader } from './GitlabUrlReader'; export { GiteaUrlReader } from './GiteaUrlReader'; +export { HarnessUrlReader } from './HarnessUrlReader'; export { AwsS3UrlReader } from './AwsS3UrlReader'; export { FetchUrlReader } from './FetchUrlReader'; export { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index a191163517..412819c5b9 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -25,7 +25,7 @@ import { ReadTreeResponseFile, } from '../types'; import { streamToBuffer } from './util'; -import { resolveSafeChildPath } from '../../paths'; +import { resolveSafeChildPath } from '@backstage/backend-plugin-api'; /** * Wraps a zip archive stream into a tree response reader. diff --git a/packages/backend-common/src/service/createServiceBuilder.ts b/packages/backend-common/src/service/createServiceBuilder.ts index a6ca25415e..e731056f72 100644 --- a/packages/backend-common/src/service/createServiceBuilder.ts +++ b/packages/backend-common/src/service/createServiceBuilder.ts @@ -19,8 +19,8 @@ import { ServiceBuilder } from './types'; /** * Creates a new service builder. - * * @public + * @deprecated We are going to deprecated this old way of creating services in a near future, if you are using this service helper, please checkout the {@link https://backstage.io/docs/backend-system/building-backends/migrating | backend} and {@link https://backstage.io/docs/backend-system/building-plugins-and-modules/migrating | plugin} migration guides. */ export function createServiceBuilder(_module: NodeModule): ServiceBuilder { return new ServiceBuilderImpl(_module); diff --git a/packages/backend-common/src/testUtils.ts b/packages/backend-common/src/testUtils.ts index 9616ab1701..397d97f20e 100644 --- a/packages/backend-common/src/testUtils.ts +++ b/packages/backend-common/src/testUtils.ts @@ -1,5 +1,5 @@ /* - * Copyright 2023 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,66 +14,30 @@ * limitations under the License. */ -import { packagePathMocks } from './paths'; -import { posix as posixPath, resolve as resolvePath } from 'path'; - -/** @public */ -export interface PackagePathResolutionOverride { - /** Restores the normal behavior of resolvePackagePath */ - restore(): void; -} - -/** @public */ -export interface OverridePackagePathResolutionOptions { - /** The name of the package to mock the resolved path of */ - packageName: string; - - /** A replacement for the root package path */ - path?: string; - - /** - * Replacements for package sub-paths, each key must be an exact match of the posix-style path - * that is being resolved within the package. - * - * For example, code calling `resolvePackagePath('x', 'foo', 'bar')` would match only the following - * configuration: `overridePackagePathResolution({ packageName: 'x', paths: { 'foo/bar': baz } })` - */ - paths?: { [path in string]: string | (() => string) }; -} +import { + overridePackagePathResolution as _overridePackagePathResolution, + OverridePackagePathResolutionOptions as _OverridePackagePathResolutionOptions, + PackagePathResolutionOverride as _PackagePathResolutionOverride, +} from '@backstage/backend-plugin-api/testUtils'; /** - * This utility helps you override the paths returned by `resolvePackagePath` for a given package. - * * @public + * @deprecated This function is deprecated and will be removed in future release, see https://github.com/backstage/backstage/issues/24493. + * Please use the `overridePackagePathResolution` function from the `@backstage/backend-plugin-api/testUtils` package instead. */ -export function overridePackagePathResolution( - options: OverridePackagePathResolutionOptions, -): PackagePathResolutionOverride { - const name = options.packageName; +export const overridePackagePathResolution = _overridePackagePathResolution; - if (packagePathMocks.has(name)) { - throw new Error( - `Tried to override resolution for '${name}' more than once for package '${name}'`, - ); - } +/** + * @public + * @deprecated This type is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + * Please use the `OverridePackagePathResolutionOptions` type from the `@backstage/backend-plugin-api/testUtils` package instead. + */ +export type OverridePackagePathResolutionOptions = + _OverridePackagePathResolutionOptions; - packagePathMocks.set(name, paths => { - const joinedPath = posixPath.join(...paths); - const localResolver = options.paths?.[joinedPath]; - if (localResolver) { - return typeof localResolver === 'function' - ? localResolver() - : localResolver; - } - if (options.path) { - return resolvePath(options.path, ...paths); - } - return undefined; - }); - - return { - restore() { - packagePathMocks.delete(name); - }, - }; -} +/** + * @public + * @deprecated This type is deprecated and will be removed in a future release, see https://github.com/backstage/backstage/issues/24493. + * Please use the `PackagePathResolutionOverride` type from the `@backstage/backend-plugin-api/testUtils` package instead. + */ +export type PackagePathResolutionOverride = _PackagePathResolutionOverride; diff --git a/packages/backend-common/src/tokens/ServerTokenManager.test.ts b/packages/backend-common/src/tokens/ServerTokenManager.test.ts index 8870b4ed1c..2f99164ec1 100644 --- a/packages/backend-common/src/tokens/ServerTokenManager.test.ts +++ b/packages/backend-common/src/tokens/ServerTokenManager.test.ts @@ -16,17 +16,17 @@ import { ConfigReader } from '@backstage/config'; import * as jose from 'jose'; -import { getVoidLogger } from '../logging'; import { ServerTokenManager } from './ServerTokenManager'; import { TokenManager } from './types'; import { DateTime } from 'luxon'; +import { mockServices } from '@backstage/backend-test-utils'; const emptyConfig = new ConfigReader({}); const configWithSecret = new ConfigReader({ backend: { auth: { keys: [{ secret: 'a-secret-key' }] } }, }); const env = process.env; -const logger = getVoidLogger(); +const logger = mockServices.logger.mock(); describe('ServerTokenManager', () => { beforeEach(() => { diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index fd311f7d2b..8019597e55 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,68 @@ # @backstage/backend-defaults +## 0.3.0-next.1 + +### Minor Changes + +- 02103be: Deprecated and moved over core services to `@backstage/backend-defaults` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-events-node@0.3.5-next.0 + +## 0.2.19-next.0 + +### Patch Changes + +- 6551b3d: Added core service factories and implementations from + `@backstage/backend-app-api`. They are now available as subpath exports, e.g. + `@backstage/backend-defaults/scheduler` is where the service factory and default + implementation of `coreServices.scheduler` now lives. They have been marked as + deprecated in their old locations. +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.2.18 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-events-node@0.3.4 + +## 0.2.18-next.2 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + ## 0.2.18-next.0 ### Patch Changes diff --git a/packages/backend-defaults/api-report-cache.md b/packages/backend-defaults/api-report-cache.md new file mode 100644 index 0000000000..2cd2f3efc9 --- /dev/null +++ b/packages/backend-defaults/api-report-cache.md @@ -0,0 +1,42 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { 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'; + +// @public +export class CacheManager { + forPlugin(pluginId: string): { + getClient(options?: CacheServiceOptions): CacheService; + }; + static fromConfig( + config: Config, + options?: { + logger?: LoggerService; + onError?: (err: Error) => void; + }, + ): CacheManager; +} + +// @public +export type CacheManagerOptions = { + logger?: LoggerService; + onError?: (err: Error) => void; +}; + +// @public (undocumented) +export const cacheServiceFactory: () => ServiceFactory; + +// @public (undocumented) +export interface PluginCacheManager { + // (undocumented) + getClient(options?: CacheServiceOptions): CacheService; +} + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/api-report-database.md b/packages/backend-defaults/api-report-database.md new file mode 100644 index 0000000000..598a3bd1b0 --- /dev/null +++ b/packages/backend-defaults/api-report-database.md @@ -0,0 +1,53 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import { DatabaseService } from '@backstage/backend-plugin-api'; +import { LifecycleService } from '@backstage/backend-plugin-api'; +import { LoggerService } from '@backstage/backend-plugin-api'; +import { PluginDatabaseManager } from '@backstage/backend-common'; +import { PluginMetadataService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public +export class DatabaseManager implements LegacyRootDatabaseService { + forPlugin( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): DatabaseService; + static fromConfig( + config: Config, + options?: DatabaseManagerOptions, + ): DatabaseManager; +} + +// @public +export type DatabaseManagerOptions = { + migrations?: DatabaseService['migrations']; + logger?: LoggerService; +}; + +// @public (undocumented) +export const databaseServiceFactory: () => ServiceFactory< + PluginDatabaseManager, + 'plugin' +>; + +// @public @deprecated +export function dropDatabase( + dbConfig: Config, + ...databaseNames: string[] +): Promise; + +// @public +export type LegacyRootDatabaseService = { + forPlugin(pluginId: string): DatabaseService; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/api-report-discovery.md b/packages/backend-defaults/api-report-discovery.md new file mode 100644 index 0000000000..0ff734b8a7 --- /dev/null +++ b/packages/backend-defaults/api-report-discovery.md @@ -0,0 +1,31 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import { DiscoveryService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public (undocumented) +export const discoveryServiceFactory: () => ServiceFactory< + DiscoveryService, + 'plugin' +>; + +// @public +export class HostDiscovery implements DiscoveryService { + static fromConfig( + config: Config, + options?: { + basePath?: string; + }, + ): HostDiscovery; + // (undocumented) + getBaseUrl(pluginId: string): Promise; + // (undocumented) + getExternalBaseUrl(pluginId: string): Promise; +} + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/api-report-lifecycle.md b/packages/backend-defaults/api-report-lifecycle.md new file mode 100644 index 0000000000..4233584664 --- /dev/null +++ b/packages/backend-defaults/api-report-lifecycle.md @@ -0,0 +1,16 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { LifecycleService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public +export const lifecycleServiceFactory: () => ServiceFactory< + LifecycleService, + 'plugin' +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/api-report-permissions.md b/packages/backend-defaults/api-report-permissions.md new file mode 100644 index 0000000000..9006a62018 --- /dev/null +++ b/packages/backend-defaults/api-report-permissions.md @@ -0,0 +1,16 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { PermissionsService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public (undocumented) +export const permissionsServiceFactory: () => ServiceFactory< + PermissionsService, + 'plugin' +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/api-report-rootConfig.md b/packages/backend-defaults/api-report-rootConfig.md new file mode 100644 index 0000000000..60c8fbcb57 --- /dev/null +++ b/packages/backend-defaults/api-report-rootConfig.md @@ -0,0 +1,24 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { RemoteConfigSourceOptions } from '@backstage/config-loader'; +import { RootConfigService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public (undocumented) +export interface RootConfigFactoryOptions { + argv?: string[]; + remote?: Pick; + // (undocumented) + watch?: boolean; +} + +// @public (undocumented) +export const rootConfigServiceFactory: ( + options?: RootConfigFactoryOptions | undefined, +) => 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 new file mode 100644 index 0000000000..00eb9c1ebb --- /dev/null +++ b/packages/backend-defaults/api-report-rootLifecycle.md @@ -0,0 +1,16 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { RootLifecycleService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public +export const rootLifecycleServiceFactory: () => ServiceFactory< + RootLifecycleService, + 'root' +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/api-report-scheduler.md b/packages/backend-defaults/api-report-scheduler.md new file mode 100644 index 0000000000..a2dad43d60 --- /dev/null +++ b/packages/backend-defaults/api-report-scheduler.md @@ -0,0 +1,16 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { SchedulerService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @public +export const schedulerServiceFactory: () => ServiceFactory< + SchedulerService, + 'plugin' +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/api-report-urlReader.md b/packages/backend-defaults/api-report-urlReader.md new file mode 100644 index 0000000000..8c7147bd7c --- /dev/null +++ b/packages/backend-defaults/api-report-urlReader.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/backend-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { UrlReader } from '@backstage/backend-common'; + +// @public (undocumented) +export const urlReaderServiceFactory: () => ServiceFactory; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-defaults/config.d.ts b/packages/backend-defaults/config.d.ts new file mode 100644 index 0000000000..569ab436db --- /dev/null +++ b/packages/backend-defaults/config.d.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + /** + * Options used by the default discovery service. + */ + discovery?: { + /** + * A list of target baseUrls and the associated plugins. + */ + endpoints: Array<{ + /** + * The target base URL to use for the plugin. + * + * Can be either a string or an object with internal and external keys. + * Targets with `{{pluginId}}` or `{{ pluginId }} in the URL will be replaced with the plugin ID. + */ + target: string | { internal: string; external: string }; + /** + * Array of plugins which use the target base URL. + */ + plugins: string[]; + }>; + }; +} diff --git a/packages/backend-defaults/migrations/scheduler/20210928160613_init.js b/packages/backend-defaults/migrations/scheduler/20210928160613_init.js new file mode 100644 index 0000000000..f9900cab11 --- /dev/null +++ b/packages/backend-defaults/migrations/scheduler/20210928160613_init.js @@ -0,0 +1,64 @@ +/* + * 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. + */ + +// @ts-check + +/** + * @param {import('knex').Knex} knex + */ +exports.up = async function up(knex) { + // + // tasks + // + await knex.schema.createTable('backstage_backend_tasks__tasks', table => { + table.comment('Tasks used for scheduling work on multiple workers'); + table + .string('id') + .primary() + .notNullable() + .comment('The unique ID of this particular task'); + table + .text('settings_json') + .notNullable() + .comment('JSON serialized object with properties for this task'); + table + .dateTime('next_run_start_at') + .notNullable() + .comment('The next time that the task should be started'); + table + .text('current_run_ticket') + .nullable() + .comment('A unique ticket for the current task run'); + table + .dateTime('current_run_started_at') + .nullable() + .comment('The time that the current task run started'); + table + .dateTime('current_run_expires_at') + .nullable() + .comment('The time that the current task run will time out'); + }); +}; + +/** + * @param {import('knex').Knex} knex + */ +exports.down = async function down(knex) { + // + // tasks + // + await knex.schema.dropTable('backstage_backend_tasks__tasks'); +}; diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 8b061b15f4..2e8c8cf757 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,46 +1,120 @@ { "name": "@backstage/backend-defaults", + "version": "0.3.0-next.1", "description": "Backend defaults used by Backstage backend apps", - "version": "0.2.18-next.0", - "main": "src/index.ts", - "types": "src/index.ts", - "publishConfig": { - "access": "public", - "main": "dist/index.cjs.js", - "types": "dist/index.d.ts" - }, "backstage": { "role": "node-library" }, + "publishConfig": { + "access": "public" + }, + "keywords": [ + "backstage" + ], "homepage": "https://backstage.io", "repository": { "type": "git", "url": "https://github.com/backstage/backstage", "directory": "packages/backend-defaults" }, - "keywords": [ - "backstage" - ], "license": "Apache-2.0", + "exports": { + ".": "./src/index.ts", + "./cache": "./src/entrypoints/cache/index.ts", + "./database": "./src/entrypoints/database/index.ts", + "./discovery": "./src/entrypoints/discovery/index.ts", + "./lifecycle": "./src/entrypoints/lifecycle/index.ts", + "./permissions": "./src/entrypoints/permissions/index.ts", + "./rootConfig": "./src/entrypoints/rootConfig/index.ts", + "./rootLifecycle": "./src/entrypoints/rootLifecycle/index.ts", + "./scheduler": "./src/entrypoints/scheduler/index.ts", + "./urlReader": "./src/entrypoints/urlReader/index.ts", + "./package.json": "./package.json" + }, + "main": "src/index.ts", + "types": "src/index.ts", + "typesVersions": { + "*": { + "cache": [ + "src/entrypoints/cache/index.ts" + ], + "database": [ + "src/entrypoints/database/index.ts" + ], + "discovery": [ + "src/entrypoints/discovery/index.ts" + ], + "lifecycle": [ + "src/entrypoints/lifecycle/index.ts" + ], + "permissions": [ + "src/entrypoints/permissions/index.ts" + ], + "rootConfig": [ + "src/entrypoints/rootConfig/index.ts" + ], + "rootLifecycle": [ + "src/entrypoints/rootLifecycle/index.ts" + ], + "scheduler": [ + "src/entrypoints/scheduler/index.ts" + ], + "urlReader": [ + "src/entrypoints/urlReader/index.ts" + ], + "package.json": [ + "package.json" + ] + } + }, + "files": [ + "config.d.ts", + "dist", + "migrations" + ], "scripts": { "build": "backstage-cli package build", + "clean": "backstage-cli package clean", "lint": "backstage-cli package lint", - "test": "backstage-cli package test", "prepack": "backstage-cli package prepack", "postpack": "backstage-cli package postpack", - "clean": "backstage-cli package clean", - "start": "backstage-cli package start" + "start": "backstage-cli package start", + "test": "backstage-cli package test" }, "dependencies": { "@backstage/backend-app-api": "workspace:^", - "@backstage/backend-common": "workspace:^" + "@backstage/backend-common": "workspace:^", + "@backstage/backend-dev-utils": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/config-loader": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", + "@backstage/types": "workspace:^", + "@keyv/memcache": "^1.3.5", + "@keyv/redis": "^2.5.3", + "@opentelemetry/api": "^1.3.0", + "better-sqlite3": "^9.0.0", + "cron": "^3.0.0", + "fs-extra": "^11.2.0", + "keyv": "^4.5.2", + "knex": "^3.0.0", + "lodash": "^4.17.21", + "luxon": "^3.0.0", + "mysql2": "^3.0.0", + "p-limit": "^3.1.0", + "pg": "^8.11.3", + "pg-connection-string": "^2.3.0", + "uuid": "^9.0.0", + "yn": "^4.0.0", + "zod": "^3.22.4" }, "devDependencies": { "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-test-utils": "workspace:^", - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "wait-for-expect": "^3.0.2" }, - "files": [ - "dist" - ] + "configSchema": "config.d.ts" } diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 5495665dd8..823b3c2833 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -16,26 +16,27 @@ import { Backend, - cacheServiceFactory, - rootConfigServiceFactory, - createSpecializedBackend, - databaseServiceFactory, - discoveryServiceFactory, - httpRouterServiceFactory, - rootHttpRouterServiceFactory, - lifecycleServiceFactory, - rootLifecycleServiceFactory, - loggerServiceFactory, - permissionsServiceFactory, - rootLoggerServiceFactory, - schedulerServiceFactory, - tokenManagerServiceFactory, - urlReaderServiceFactory, - identityServiceFactory, authServiceFactory, + createSpecializedBackend, httpAuthServiceFactory, + httpRouterServiceFactory, + identityServiceFactory, + loggerServiceFactory, + rootHttpRouterServiceFactory, + rootLoggerServiceFactory, + tokenManagerServiceFactory, userInfoServiceFactory, } from '@backstage/backend-app-api'; +import { cacheServiceFactory } from '@backstage/backend-defaults/cache'; +import { databaseServiceFactory } from '@backstage/backend-defaults/database'; +import { discoveryServiceFactory } from '@backstage/backend-defaults/discovery'; +import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle'; +import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions'; +import { rootConfigServiceFactory } from '@backstage/backend-defaults/rootConfig'; +import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; +import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; +import { urlReaderServiceFactory } from '@backstage/backend-defaults/urlReader'; +import { eventsServiceFactory } from '@backstage/plugin-events-node'; export const defaultServiceFactories = [ authServiceFactory(), @@ -56,6 +57,7 @@ export const defaultServiceFactories = [ tokenManagerServiceFactory(), userInfoServiceFactory(), urlReaderServiceFactory(), + eventsServiceFactory(), ]; /** diff --git a/packages/backend-common/src/cache/CacheClient.test.ts b/packages/backend-defaults/src/entrypoints/cache/CacheClient.test.ts similarity index 100% rename from packages/backend-common/src/cache/CacheClient.test.ts rename to packages/backend-defaults/src/entrypoints/cache/CacheClient.test.ts diff --git a/packages/backend-common/src/cache/CacheClient.ts b/packages/backend-defaults/src/entrypoints/cache/CacheClient.ts similarity index 100% rename from packages/backend-common/src/cache/CacheClient.ts rename to packages/backend-defaults/src/entrypoints/cache/CacheClient.ts diff --git a/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts b/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts new file mode 100644 index 0000000000..6eb907764d --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mockServices, TestCaches } from '@backstage/backend-test-utils'; +import KeyvRedis from '@keyv/redis'; +import KeyvMemcache from '@keyv/memcache'; +import { CacheManager } from './CacheManager'; + +// This test is in a separate file because the main test file uses other mocking +// that might interfere with this one. + +// Contrived code because it's hard to spy on a default export +jest.mock('@keyv/redis', () => { + const Actual = jest.requireActual('@keyv/redis'); + return jest.fn((...args: any[]) => { + return new Actual(...args); + }); +}); +jest.mock('@keyv/memcache', () => { + const Actual = jest.requireActual('@keyv/memcache'); + return jest.fn((...args: any[]) => { + return new Actual(...args); + }); +}); + +describe('CacheManager integration', () => { + const caches = TestCaches.create(); + + afterEach(jest.clearAllMocks); + + it.each(caches.eachSupportedId())( + 'only creates one underlying connection, %p', + async cacheId => { + const { store, connection } = await caches.init(cacheId); + + const manager = CacheManager.fromConfig( + mockServices.rootConfig({ + data: { backend: { cache: { store, connection } } }, + }), + ); + + manager.forPlugin('p1').getClient(); + manager.forPlugin('p1').getClient({ defaultTtl: 200 }); + manager.forPlugin('p2').getClient(); + manager.forPlugin('p3').getClient({}); + + if (store === 'redis') { + // eslint-disable-next-line jest/no-conditional-expect + expect(KeyvRedis).toHaveBeenCalledTimes(1); + } else if (store === 'memcache') { + // eslint-disable-next-line jest/no-conditional-expect + expect(KeyvMemcache).toHaveBeenCalledTimes(1); + } + }, + ); + + it.each(caches.eachSupportedId())( + 'interacts correctly with store, %p', + async cacheId => { + const { store, connection } = await caches.init(cacheId); + + const manager = CacheManager.fromConfig( + mockServices.rootConfig({ + data: { + backend: { cache: { store, connection } }, + }, + }), + ); + + const plugin1 = manager.forPlugin('p1').getClient(); + const plugin2a = manager.forPlugin('p2').getClient(); + const plugin2b = manager.forPlugin('p2').getClient({ defaultTtl: 2000 }); + + await plugin1.set('a', 'plugin1'); + await plugin2a.set('a', 'plugin2a'); + await plugin2b.set('a', 'plugin2b'); + + await expect(plugin1.get('a')).resolves.toBe('plugin1'); + await expect(plugin2a.get('a')).resolves.toBe('plugin2b'); + await expect(plugin2b.get('a')).resolves.toBe('plugin2b'); + }, + ); +}); diff --git a/packages/backend-common/src/cache/CacheManager.ts b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts similarity index 65% rename from packages/backend-common/src/cache/CacheManager.ts rename to packages/backend-defaults/src/entrypoints/cache/CacheManager.ts index c7298ab3e9..70f952ea46 100644 --- a/packages/backend-common/src/cache/CacheManager.ts +++ b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts @@ -14,18 +14,24 @@ * limitations under the License. */ -import { Config } from '@backstage/config'; -import Keyv from 'keyv'; -import KeyvMemcache from '@keyv/memcache'; -import KeyvRedis from '@keyv/redis'; import { CacheService, CacheServiceOptions, LoggerService, } from '@backstage/backend-plugin-api'; -import { getRootLogger } from '../logging'; +import { Config } from '@backstage/config'; +import Keyv from 'keyv'; import { DefaultCacheClient } from './CacheClient'; -import { CacheManagerOptions, PluginCacheManager } from './types'; +import { CacheManagerOptions } from './types'; + +type StoreFactory = (pluginId: string, defaultTtl: number | undefined) => Keyv; + +/* + * TODO(freben): This class intentionally inlines the CacheManagerOptions and + * PluginCacheManager types, to not break the api reports in backend-common + * which re-exports it. When backend-common is deprecated, we can stop inlining + * those types. + */ /** * Implements a Cache Manager which will automatically create new cache clients @@ -40,19 +46,12 @@ export class CacheManager { * that return Keyv instances appropriate to the store. */ private readonly storeFactories = { - redis: this.getRedisClient, - memcache: this.getMemcacheClient, - memory: this.getMemoryClient, + redis: this.createRedisStoreFactory(), + memcache: this.createMemcacheStoreFactory(), + memory: this.createMemoryStoreFactory(), }; - /** - * Shared memory store for the in-memory cache client. Sharing the same Map - * instance ensures get/set/delete operations hit the same store, regardless - * of where/when a client is instantiated. - */ - private readonly memoryStore = new Map(); - - private readonly logger: LoggerService; + private readonly logger?: LoggerService; private readonly store: keyof CacheManager['storeFactories']; private readonly connection: string; private readonly useRedisSets: boolean; @@ -67,7 +66,18 @@ export class CacheManager { */ static fromConfig( config: Config, - options: CacheManagerOptions = {}, + options: { + /** + * An optional logger for use by the PluginCacheManager. + */ + logger?: LoggerService; + + /** + * An optional handler for connection errors emitted from the underlying data + * store. + */ + onError?: (err: Error) => void; + } = {}, ): CacheManager { // If no `backend.cache` config is provided, instantiate the CacheManager // with an in-memory cache client. @@ -77,25 +87,26 @@ export class CacheManager { config.getOptionalString('backend.cache.connection') || ''; const useRedisSets = config.getOptionalBoolean('backend.cache.useRedisSets') ?? true; - const logger = (options.logger || getRootLogger()).child({ + const logger = options.logger?.child({ type: 'cacheManager', }); return new CacheManager( store, connectionString, useRedisSets, - logger, options.onError, + logger, defaultTtl, ); } - private constructor( + /** @internal */ + constructor( store: string, connectionString: string, useRedisSets: boolean, - logger: LoggerService, errorHandler: CacheManagerOptions['onError'], + logger?: LoggerService, defaultTtl?: number, ) { if (!this.storeFactories.hasOwnProperty(store)) { @@ -115,7 +126,9 @@ export class CacheManager { * @param pluginId - The plugin that the cache manager should be created for. * Plugin names should be unique. */ - forPlugin(pluginId: string): PluginCacheManager { + forPlugin(pluginId: string): { + getClient(options?: CacheServiceOptions): CacheService; + } { return { getClient: (defaultOptions = {}) => { const clientFactory = (options: CacheServiceOptions) => { @@ -127,7 +140,7 @@ export class CacheManager { // 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); + this.logger?.error('Failed to create cache client', err); // Invoke any custom error handler if provided. if (typeof this.errorHandler === 'function') { @@ -148,49 +161,47 @@ export class CacheManager { } private getClientWithTtl(pluginId: string, ttl: number | undefined): Keyv { - return this.storeFactories[this.store].call(this, pluginId, ttl); + return this.storeFactories[this.store](pluginId, ttl); } - private getRedisClient( - pluginId: string, - defaultTtl: number | undefined, - ): Keyv { - return new Keyv({ - namespace: pluginId, - ttl: defaultTtl, - store: new KeyvRedis(this.connection), - useRedisSets: this.useRedisSets, - }); + private createRedisStoreFactory(): StoreFactory { + const KeyvRedis = require('@keyv/redis'); + let store: typeof KeyvRedis | undefined; + return (pluginId, defaultTtl) => { + if (!store) { + store = new KeyvRedis(this.connection); + } + return new Keyv({ + namespace: pluginId, + ttl: defaultTtl, + store, + useRedisSets: this.useRedisSets, + }); + }; } - private getMemcacheClient( - pluginId: string, - defaultTtl: number | undefined, - ): Keyv { - return new Keyv({ - namespace: pluginId, - ttl: defaultTtl, - store: new KeyvMemcache(this.connection), - }); + private createMemcacheStoreFactory(): StoreFactory { + const KeyvMemcache = require('@keyv/memcache'); + let store: typeof KeyvMemcache | undefined; + return (pluginId, defaultTtl) => { + if (!store) { + store = new KeyvMemcache(this.connection); + } + return new Keyv({ + namespace: pluginId, + ttl: defaultTtl, + store, + }); + }; } - private getMemoryClient( - pluginId: string, - defaultTtl: number | undefined, - ): Keyv { - return new Keyv({ - namespace: pluginId, - ttl: defaultTtl, - store: this.memoryStore, - }); + private createMemoryStoreFactory(): StoreFactory { + const store = new Map(); + return (pluginId, defaultTtl) => + new Keyv({ + namespace: pluginId, + ttl: defaultTtl, + store, + }); } } - -/** @public */ -export function cacheToPluginCacheManager( - cache: CacheService, -): PluginCacheManager { - return { - getClient: (opts: CacheServiceOptions) => cache.withOptions(opts), - }; -} diff --git a/plugins/user-settings-backend/src/run.ts b/packages/backend-defaults/src/entrypoints/cache/cacheServiceFactory.ts similarity index 51% rename from plugins/user-settings-backend/src/run.ts rename to packages/backend-defaults/src/entrypoints/cache/cacheServiceFactory.ts index 178de0f786..f60d770644 100644 --- a/plugins/user-settings-backend/src/run.ts +++ b/packages/backend-defaults/src/entrypoints/cache/cacheServiceFactory.ts @@ -14,21 +14,26 @@ * limitations under the License. */ -import { getRootLogger } from '@backstage/backend-common'; -import yn from 'yn'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { CacheManager } from './CacheManager'; -import { startStandaloneServer } from './service/standaloneServer'; - -const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007; -const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); -const logger = getRootLogger(); - -startStandaloneServer({ port, enableCors, logger }).catch(err => { - logger.error(err); - process.exit(1); -}); - -process.on('SIGINT', () => { - logger.info('CTRL+C pressed; exiting.'); - process.exit(0); +/** + * @public + */ +export const cacheServiceFactory = createServiceFactory({ + service: coreServices.cache, + deps: { + config: coreServices.rootConfig, + plugin: coreServices.pluginMetadata, + logger: coreServices.rootLogger, + }, + async createRootContext({ config, logger }) { + return CacheManager.fromConfig(config, { logger }); + }, + async factory({ plugin }, manager) { + return manager.forPlugin(plugin.getId()).getClient(); + }, }); diff --git a/packages/backend-defaults/src/entrypoints/cache/index.ts b/packages/backend-defaults/src/entrypoints/cache/index.ts new file mode 100644 index 0000000000..b16fa56bd2 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/cache/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { cacheServiceFactory } from './cacheServiceFactory'; +export { CacheManager } from './CacheManager'; +export type { CacheManagerOptions, PluginCacheManager } from './types'; diff --git a/packages/backend-defaults/src/entrypoints/cache/types.ts b/packages/backend-defaults/src/entrypoints/cache/types.ts new file mode 100644 index 0000000000..ccb3ed5f6d --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/cache/types.ts @@ -0,0 +1,46 @@ +/* + * 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 { LoggerService } from '@backstage/backend-plugin-api'; +import { + CacheService, + CacheServiceOptions, +} from '@backstage/backend-plugin-api'; + +/** + * Options given when constructing a {@link CacheManager}. + * + * @public + */ +export type CacheManagerOptions = { + /** + * An optional logger for use by the PluginCacheManager. + */ + logger?: LoggerService; + + /** + * An optional handler for connection errors emitted from the underlying data + * store. + */ + onError?: (err: Error) => void; +}; + +/** + * @public + */ +export interface PluginCacheManager { + getClient(options?: CacheServiceOptions): CacheService; +} diff --git a/packages/backend-defaults/src/entrypoints/database/DatabaseManager.test.ts b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.test.ts new file mode 100644 index 0000000000..347ec742c0 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.test.ts @@ -0,0 +1,123 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigReader } from '@backstage/config'; +import { DatabaseManagerImpl } from './DatabaseManager'; +import { Connector } from './types'; + +describe('DatabaseManagerImpl', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('calls the right connector, only once per plugin id', async () => { + const connector1 = { + getClient: jest.fn(), + dropDatabase: jest.fn(), + } satisfies Connector; + const connector2 = { + getClient: jest.fn(), + dropDatabase: jest.fn(), + } satisfies Connector; + + const impl = new DatabaseManagerImpl( + new ConfigReader({ + client: 'pg', + }), + { + pg: connector1, + notpg: connector2, + }, + ); + + await impl.forPlugin('plugin1').getClient(); + expect(connector1.getClient).toHaveBeenCalledTimes(1); + expect(connector1.getClient).toHaveBeenLastCalledWith('plugin1', undefined); + expect(connector2.getClient).toHaveBeenCalledTimes(0); + + await impl.forPlugin('plugin1').getClient(); + expect(connector1.getClient).toHaveBeenCalledTimes(1); + expect(connector1.getClient).toHaveBeenLastCalledWith('plugin1', undefined); + expect(connector2.getClient).toHaveBeenCalledTimes(0); + + await impl.forPlugin('plugin2').getClient(); + expect(connector1.getClient).toHaveBeenCalledTimes(2); + expect(connector1.getClient).toHaveBeenLastCalledWith('plugin2', undefined); + expect(connector2.getClient).toHaveBeenCalledTimes(0); + }); + + it('respects per-plugin overridden connectors', async () => { + const connector1 = { + getClient: jest.fn(), + dropDatabase: jest.fn(), + } satisfies Connector; + const connector2 = { + getClient: jest.fn(), + dropDatabase: jest.fn(), + } satisfies Connector; + + const impl = new DatabaseManagerImpl( + new ConfigReader({ + client: 'pg', + plugin: { + plugin2: { + client: 'mysql', + }, + }, + }), + { + pg: connector1, + mysql: connector2, + }, + ); + + await impl.forPlugin('plugin1').getClient(); + expect(connector1.getClient).toHaveBeenCalledTimes(1); + expect(connector1.getClient).toHaveBeenLastCalledWith('plugin1', undefined); + expect(connector2.getClient).toHaveBeenCalledTimes(0); + + await impl.forPlugin('plugin2').getClient(); + expect(connector1.getClient).toHaveBeenCalledTimes(1); + expect(connector1.getClient).toHaveBeenLastCalledWith('plugin1', undefined); + expect(connector2.getClient).toHaveBeenCalledTimes(1); + expect(connector2.getClient).toHaveBeenLastCalledWith('plugin2', undefined); + }); + + it('retains the migration skip info', async () => { + const connector = { + getClient: jest.fn(), + dropDatabase: jest.fn(), + } satisfies Connector; + + const impl1 = new DatabaseManagerImpl(new ConfigReader({ client: 'pg' }), { + pg: connector, + }); + + const impl2 = new DatabaseManagerImpl( + new ConfigReader({ client: 'pg' }), + { pg: connector }, + { migrations: { skip: true } }, + ); + + expect((await impl1.forPlugin('plugin1')).migrations).toEqual({ + skip: false, + }); + + expect((await impl2.forPlugin('plugin1')).migrations).toEqual({ + skip: true, + }); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts new file mode 100644 index 0000000000..7e3adf17df --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts @@ -0,0 +1,254 @@ +/* + * 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 { + DatabaseService, + LifecycleService, + LoggerService, + PluginMetadataService, +} from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { stringifyError } from '@backstage/errors'; +import { Knex } from 'knex'; +import { MysqlConnector } from './connectors/mysql'; +import { PgConnector } from './connectors/postgres'; +import { Sqlite3Connector } from './connectors/sqlite3'; +import { Connector, PluginDatabaseManager } from './types'; + +/** + * Provides a config lookup path for a plugin's config block. + */ +function pluginPath(pluginId: string): string { + return `plugin.${pluginId}`; +} + +/** + * Creation options for {@link DatabaseManager}. + * + * @public + */ +export type DatabaseManagerOptions = { + migrations?: DatabaseService['migrations']; + logger?: LoggerService; +}; + +/** + * An interface that represents the legacy global DatabaseManager implementation. + * @public + */ +export type LegacyRootDatabaseService = { + forPlugin(pluginId: string): DatabaseService; +}; + +/** + * Testable implementation class for {@link DatabaseManager} below. + */ +export class DatabaseManagerImpl implements LegacyRootDatabaseService { + constructor( + private readonly config: Config, + private readonly connectors: Record, + private readonly options?: DatabaseManagerOptions, + private readonly databaseCache: Map> = new Map(), + ) {} + + /** + * Generates a PluginDatabaseManager for consumption by plugins. + * + * @param pluginId - The plugin that the database manager should be created for. Plugin names + * should be unique as they are used to look up database config overrides under + * `backend.database.plugin`. + */ + forPlugin( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): PluginDatabaseManager { + const client = this.getClientType(pluginId).client; + const connector = this.connectors[client]; + if (!connector) { + throw new Error( + `Unsupported database client type '${client}' specified for plugin '${pluginId}'`, + ); + } + const getClient = () => this.getDatabase(pluginId, connector, deps); + const migrations = { skip: false, ...this.options?.migrations }; + return { getClient, migrations }; + } + + /** + * Provides the client type which should be used for a given plugin. + * + * The client type is determined by plugin specific config if present. + * Otherwise the base client is used as the fallback. + * + * @param pluginId - Plugin to get the client type for + * @returns Object with client type returned as `client` and boolean + * representing whether or not the client was overridden as + * `overridden` + */ + private getClientType(pluginId: string): { + client: string; + overridden: boolean; + } { + const pluginClient = this.config.getOptionalString( + `${pluginPath(pluginId)}.client`, + ); + + const baseClient = this.config.getString('client'); + const client = pluginClient ?? baseClient; + return { + client, + overridden: client !== baseClient, + }; + } + + /** + * Provides a scoped Knex client for a plugin as per application config. + * + * @param pluginId - Plugin to get a Knex client for + * @returns Promise which resolves to a scoped Knex database client for a + * plugin + */ + private async getDatabase( + pluginId: string, + connector: Connector, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): Promise { + if (this.databaseCache.has(pluginId)) { + return this.databaseCache.get(pluginId)!; + } + + const clientPromise = connector.getClient(pluginId, deps); + this.databaseCache.set(pluginId, clientPromise); + + if (process.env.NODE_ENV !== 'test') { + clientPromise.then(client => this.startKeepaliveLoop(pluginId, client)); + } + + return clientPromise; + } + + private startKeepaliveLoop(pluginId: string, client: Knex): void { + let lastKeepaliveFailed = false; + + setInterval(() => { + // During testing it can happen that the environment is torn down and + // this client is `undefined`, but this interval is still run. + client?.raw('select 1').then( + () => { + lastKeepaliveFailed = false; + }, + (error: unknown) => { + if (!lastKeepaliveFailed) { + lastKeepaliveFailed = true; + this.options?.logger?.warn( + `Database keepalive failed for plugin ${pluginId}, ${stringifyError( + error, + )}`, + ); + } + }, + ); + }, 60 * 1000); + } +} + +// NOTE: This class looks odd but is kept around for API compatibility reasons +/** + * Manages database connections for Backstage backend plugins. + * + * @public + * @remarks + * + * The database manager allows the user to set connection and client settings on + * a per pluginId basis by defining a database config block under + * `plugin.` in addition to top level defaults. Optionally, a user may + * set `prefix` which is used to prefix generated database names if config is + * not provided. + */ +export class DatabaseManager implements LegacyRootDatabaseService { + /** + * Creates a {@link DatabaseManager} from `backend.database` config. + * + * @param config - The loaded application configuration. + * @param options - An optional configuration object. + */ + static fromConfig( + config: Config, + options?: DatabaseManagerOptions, + ): DatabaseManager { + const databaseConfig = config.getConfig('backend.database'); + const prefix = + databaseConfig.getOptionalString('prefix') || 'backstage_plugin_'; + return new DatabaseManager( + new DatabaseManagerImpl( + databaseConfig, + { + pg: new PgConnector(databaseConfig, prefix), + sqlite3: new Sqlite3Connector(databaseConfig), + 'better-sqlite3': new Sqlite3Connector(databaseConfig), + mysql: new MysqlConnector(databaseConfig, prefix), + mysql2: new MysqlConnector(databaseConfig, prefix), + }, + options, + ), + ); + } + + private constructor(private readonly impl: DatabaseManagerImpl) {} + + /** + * Generates a PluginDatabaseManager for consumption by plugins. + * + * @param pluginId - The plugin that the database manager should be created for. Plugin names + * should be unique as they are used to look up database config overrides under + * `backend.database.plugin`. + */ + forPlugin( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): PluginDatabaseManager { + return this.impl.forPlugin(pluginId, deps); + } +} + +/** + * Helper for deleting databases. + * + * @public + * @deprecated Will be removed in a future release. + */ +export async function dropDatabase( + dbConfig: Config, + ...databaseNames: string[] +): Promise { + const client = dbConfig.getString('client'); + const prefix = dbConfig.getOptionalString('prefix') || 'backstage_plugin_'; + + if (client === 'pg') { + await new PgConnector(dbConfig, prefix).dropDatabase(...databaseNames); + } else if (client === 'mysql' || client === 'mysql2') { + await new MysqlConnector(dbConfig, prefix).dropDatabase(...databaseNames); + } +} diff --git a/packages/backend-common/src/database/connectors/defaultNameOverride.test.ts b/packages/backend-defaults/src/entrypoints/database/connectors/defaultNameOverride.test.ts similarity index 99% rename from packages/backend-common/src/database/connectors/defaultNameOverride.test.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/defaultNameOverride.test.ts index 1da8e6c11e..59f7b5b137 100644 --- a/packages/backend-common/src/database/connectors/defaultNameOverride.test.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/defaultNameOverride.test.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import defaultNameOverride from './defaultNameOverride'; describe('defaultNameOverride()', () => { diff --git a/packages/backend-common/src/database/connectors/defaultNameOverride.ts b/packages/backend-defaults/src/entrypoints/database/connectors/defaultNameOverride.ts similarity index 99% rename from packages/backend-common/src/database/connectors/defaultNameOverride.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/defaultNameOverride.ts index bc467eb7f6..3f610c51c6 100644 --- a/packages/backend-common/src/database/connectors/defaultNameOverride.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/defaultNameOverride.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Knex } from 'knex'; /** diff --git a/packages/backend-common/src/database/connectors/defaultSchemaOverride.test.ts b/packages/backend-defaults/src/entrypoints/database/connectors/defaultSchemaOverride.test.ts similarity index 99% rename from packages/backend-common/src/database/connectors/defaultSchemaOverride.test.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/defaultSchemaOverride.test.ts index 2db5ecd454..505b9051f7 100644 --- a/packages/backend-common/src/database/connectors/defaultSchemaOverride.test.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/defaultSchemaOverride.test.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import defaultSchemaOverride from './defaultSchemaOverride'; describe('defaultNameOverride()', () => { diff --git a/packages/backend-common/src/database/connectors/defaultSchemaOverride.ts b/packages/backend-defaults/src/entrypoints/database/connectors/defaultSchemaOverride.ts similarity index 99% rename from packages/backend-common/src/database/connectors/defaultSchemaOverride.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/defaultSchemaOverride.ts index 4e76308542..85c6f1ec65 100644 --- a/packages/backend-common/src/database/connectors/defaultSchemaOverride.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/defaultSchemaOverride.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Knex } from 'knex'; /** diff --git a/packages/backend-common/src/database/connectors/index.ts b/packages/backend-defaults/src/entrypoints/database/connectors/index.ts similarity index 99% rename from packages/backend-common/src/database/connectors/index.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/index.ts index df84ec66ba..9d18e7460a 100644 --- a/packages/backend-common/src/database/connectors/index.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/index.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export * from './mysql'; export * from './postgres'; export * from './sqlite3'; diff --git a/packages/backend-common/src/database/config.test.ts b/packages/backend-defaults/src/entrypoints/database/connectors/mergeDatabaseConfig.test.ts similarity index 97% rename from packages/backend-common/src/database/config.test.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/mergeDatabaseConfig.test.ts index a5bf4a79d2..84177a1208 100644 --- a/packages/backend-common/src/database/config.test.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/mergeDatabaseConfig.test.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { mergeDatabaseConfig } from './config'; +import { mergeDatabaseConfig } from './mergeDatabaseConfig'; -describe('config', () => { +describe('mergeDatabaseConfig', () => { describe('mergeDatabaseConfig', () => { it('does not mutate the input object', () => { const input = { diff --git a/packages/backend-common/src/database/config.ts b/packages/backend-defaults/src/entrypoints/database/connectors/mergeDatabaseConfig.ts similarity index 100% rename from packages/backend-common/src/database/config.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/mergeDatabaseConfig.ts diff --git a/packages/backend-common/src/database/connectors/mysql.test.ts b/packages/backend-defaults/src/entrypoints/database/connectors/mysql.test.ts similarity index 100% rename from packages/backend-common/src/database/connectors/mysql.test.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/mysql.test.ts diff --git a/packages/backend-defaults/src/entrypoints/database/connectors/mysql.ts b/packages/backend-defaults/src/entrypoints/database/connectors/mysql.ts new file mode 100644 index 0000000000..2fb3545047 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/connectors/mysql.ts @@ -0,0 +1,480 @@ +/* + * 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 { + LifecycleService, + PluginMetadataService, +} from '@backstage/backend-plugin-api'; +import { Config, ConfigReader } from '@backstage/config'; +import { InputError } from '@backstage/errors'; +import { JsonObject } from '@backstage/types'; +import knexFactory, { Knex } from 'knex'; +import { merge, omit } from 'lodash'; +import limiterFactory from 'p-limit'; +import yn from 'yn'; +import { Connector, DatabaseConnector } from '../types'; +import defaultNameOverride from './defaultNameOverride'; +import { mergeDatabaseConfig } from './mergeDatabaseConfig'; + +// Limits the number of concurrent DDL operations to 1 +const ddlLimiter = limiterFactory(1); + +/** + * Creates a knex mysql database connection + * + * @param dbConfig - The database config + * @param overrides - Additional options to merge with the config + */ +export function createMysqlDatabaseClient( + dbConfig: Config, + overrides?: Knex.Config, +) { + const knexConfig = buildMysqlDatabaseConfig(dbConfig, overrides); + const database = knexFactory(knexConfig); + return database; +} + +/** + * Builds a knex mysql database connection + * + * @param dbConfig - The database config + * @param overrides - Additional options to merge with the config + */ +export function buildMysqlDatabaseConfig( + dbConfig: Config, + overrides?: Knex.Config, +) { + return mergeDatabaseConfig( + dbConfig.get(), + { + connection: getMysqlConnectionConfig(dbConfig, !!overrides), + useNullAsDefault: true, + }, + overrides, + ); +} + +/** + * Gets the mysql connection config + * + * @param dbConfig - The database config + * @param parseConnectionString - Flag to explicitly control connection string parsing + */ +export function getMysqlConnectionConfig( + dbConfig: Config, + parseConnectionString?: boolean, +): Knex.MySqlConnectionConfig | string { + const connection = dbConfig.get('connection') as any; + const isConnectionString = + typeof connection === 'string' || connection instanceof String; + const autoParse = typeof parseConnectionString !== 'boolean'; + + const shouldParseConnectionString = autoParse + ? isConnectionString + : parseConnectionString && isConnectionString; + + return shouldParseConnectionString + ? parseMysqlConnectionString(connection as string) + : connection; +} + +/** + * Parses a mysql connection string. + * + * e.g. mysql://examplename:somepassword@examplehost:3306/dbname + * @param connectionString - The mysql connection string + */ +export function parseMysqlConnectionString( + connectionString: string, +): Knex.MySqlConnectionConfig { + try { + const { + protocol, + username, + password, + port, + hostname, + pathname, + searchParams, + } = new URL(connectionString); + + if (protocol !== 'mysql:') { + throw new Error(`Unknown protocol ${protocol}`); + } else if (!username || !password) { + throw new Error(`Missing username/password`); + } else if (!pathname.match(/^\/[^/]+$/)) { + throw new Error(`Expected single path segment`); + } + + const result: Knex.MySqlConnectionConfig = { + user: username, + password, + host: hostname, + port: Number(port || 3306), + database: decodeURIComponent(pathname.substring(1)), + }; + + const ssl = searchParams.get('ssl'); + if (ssl) { + result.ssl = ssl; + } + + const debug = searchParams.get('debug'); + if (debug) { + result.debug = yn(debug); + } + + return result; + } catch (e) { + throw new InputError( + `Error while parsing MySQL connection string, ${e}`, + e, + ); + } +} + +/** + * Creates the missing mysql database if it does not exist + * + * @param dbConfig - The database config + * @param databases - The names of the databases to create + */ +export async function ensureMysqlDatabaseExists( + dbConfig: Config, + ...databases: Array +) { + const admin = createMysqlDatabaseClient(dbConfig, { + connection: { + database: null as unknown as string, + }, + pool: { + min: 0, + acquireTimeoutMillis: 10000, + }, + }); + + try { + const ensureDatabase = async (database: string) => { + await admin.raw(`CREATE DATABASE IF NOT EXISTS ??`, [database]); + }; + await Promise.all( + databases.map(async database => { + // For initial setup we use a smaller timeout but several retries. Given that this + // is a separate connection pool we should never really run into issues with connection + // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency. + let lastErr: Error | undefined = undefined; + for (let i = 0; i < 3; i++) { + try { + return await ddlLimiter(() => ensureDatabase(database)); + } catch (err) { + lastErr = err; + } + await new Promise(resolve => setTimeout(resolve, 100)); + } + throw lastErr; + }), + ); + } finally { + await admin.destroy(); + } +} + +/** + * Drops the given mysql databases. + * + * @param dbConfig - The database config + * @param databases - The names of the databases to create + */ +export async function dropMysqlDatabase( + dbConfig: Config, + ...databases: Array +) { + const admin = createMysqlDatabaseClient(dbConfig, { + connection: { + database: null as unknown as string, + }, + pool: { + min: 0, + acquireTimeoutMillis: 10000, + }, + }); + + try { + const dropDatabase = async (database: string) => { + await admin.raw(`DROP DATABASE ??`, [database]); + }; + await Promise.all( + databases.map(async database => { + return await ddlLimiter(() => dropDatabase(database)); + }), + ); + } finally { + await admin.destroy(); + } +} + +/** + * MySQL database connector. + * + * Exposes database connector functionality via an immutable object. + */ +export const mysqlConnector: DatabaseConnector = Object.freeze({ + createClient: createMysqlDatabaseClient, + ensureDatabaseExists: ensureMysqlDatabaseExists, + createNameOverride: defaultNameOverride, + parseConnectionString: parseMysqlConnectionString, + dropDatabase: dropMysqlDatabase, +}); + +/** + * Provides a config lookup path for a plugin's config block. + */ +function pluginPath(pluginId: string): string { + return `plugin.${pluginId}`; +} + +function normalizeConnection( + connection: Knex.StaticConnectionConfig | JsonObject | string | undefined, + client: string, +): Partial { + if (typeof connection === 'undefined' || connection === null) { + return {}; + } + + return typeof connection === 'string' || connection instanceof String + ? mysqlConnector.parseConnectionString(connection as string, client) + : connection; +} + +function createNameOverride( + client: string, + name: string, +): Partial { + try { + return mysqlConnector.createNameOverride(name); + } catch (e) { + throw new InputError( + `Unable to create database name override for '${client}' connector`, + e, + ); + } +} + +export class MysqlConnector implements Connector { + constructor( + private readonly config: Config, + private readonly prefix: string, + ) {} + + async getClient( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): Promise { + const pluginConfig = new ConfigReader( + this.getConfigForPlugin(pluginId) as JsonObject, + ); + + const databaseName = this.getDatabaseName(pluginId); + if (databaseName && this.getEnsureExistsConfig(pluginId)) { + try { + await mysqlConnector.ensureDatabaseExists!(pluginConfig, databaseName); + } catch (error) { + throw new Error( + `Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`, + ); + } + } + + const pluginDivisionMode = this.getPluginDivisionModeConfig(); + if (pluginDivisionMode !== 'database') { + throw new Error( + `The MySQL driver does not support plugin division mode '${pluginDivisionMode}'`, + ); + } + + const databaseClientOverrides = mergeDatabaseConfig( + {}, + this.getDatabaseOverrides(pluginId), + ); + + const client = mysqlConnector.createClient( + pluginConfig, + databaseClientOverrides, + deps, + ); + + return client; + } + + async dropDatabase(...databaseNames: string[]): Promise { + return await dropMysqlDatabase(this.config, ...databaseNames); + } + + /** + * Provides the canonical database name for a given plugin. + * + * This method provides the effective database name which is determined using + * global and plugin specific database config. If no explicit database name, + * this method will provide a generated name which is the pluginId prefixed + * with 'backstage_plugin_'. + * + * @param pluginId - Lookup the database name for given plugin + * @returns String representing the plugin's database name + */ + private getDatabaseName(pluginId: string): string | undefined { + const connection = this.getConnectionConfig(pluginId); + const databaseName = (connection as Knex.ConnectionConfig)?.database; + return databaseName ?? `${this.prefix}${pluginId}`; + } + + /** + * Provides the client type which should be used for a given plugin. + * + * The client type is determined by plugin specific config if present. + * Otherwise the base client is used as the fallback. + * + * @param pluginId - Plugin to get the client type for + * @returns Object with client type returned as `client` and boolean + * representing whether or not the client was overridden as + * `overridden` + */ + private getClientType(pluginId: string): { + client: string; + overridden: boolean; + } { + const pluginClient = this.config.getOptionalString( + `${pluginPath(pluginId)}.client`, + ); + + const baseClient = this.config.getString('client'); + const client = pluginClient ?? baseClient; + return { + client, + overridden: client !== baseClient, + }; + } + + private getRoleConfig(pluginId: string): string | undefined { + return ( + this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ?? + this.config.getOptionalString('role') + ); + } + + /** + * Provides the knexConfig which should be used for a given plugin. + * + * @param pluginId - Plugin to get the knexConfig for + * @returns The merged knexConfig value or undefined if it isn't specified + */ + private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined { + const pluginConfig = this.config + .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`) + ?.get(); + + const baseConfig = this.config + .getOptionalConfig('knexConfig') + ?.get(); + + return merge(baseConfig, pluginConfig); + } + + private getEnsureExistsConfig(pluginId: string): boolean { + const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true; + return ( + this.config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ?? + baseConfig + ); + } + + private getPluginDivisionModeConfig(): string { + return this.config.getOptionalString('pluginDivisionMode') ?? 'database'; + } + + /** + * Provides a Knex connection plugin config by combining base and plugin + * config. + * + * This method provides a baseConfig for a plugin database connector. If the + * client type has not been overridden, the global connection config will be + * included with plugin specific config as the base. Values from the plugin + * connection take precedence over the base. Base database name is omitted + * unless `pluginDivisionMode` is set to `schema`. + */ + private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig { + const { client, overridden } = this.getClientType(pluginId); + + let baseConnection = normalizeConnection( + this.config.get('connection'), + this.config.getString('client'), + ); + + // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The + // `database` property from the base connection is omitted unless `pluginDivisionMode` + // is set to `schema`. + if (this.getPluginDivisionModeConfig() !== 'schema') { + baseConnection = omit(baseConnection, 'database'); + } + + // get and normalize optional plugin specific database connection + const connection = normalizeConnection( + this.config.getOptional(`${pluginPath(pluginId)}.connection`), + client, + ); + + return { + // include base connection if client type has not been overridden + ...(overridden ? {} : baseConnection), + ...connection, + } as Knex.StaticConnectionConfig; + } + + /** + * Provides a Knex database config for a given plugin. + * + * This method provides a Knex configuration object along with the plugin's + * client type. + * + * @param pluginId - The plugin that the database config should correspond with + */ + private getConfigForPlugin(pluginId: string): Knex.Config { + const { client } = this.getClientType(pluginId); + const role = this.getRoleConfig(pluginId); + + return { + ...this.getAdditionalKnexConfig(pluginId), + client, + connection: this.getConnectionConfig(pluginId), + ...(role && { role }), + }; + } + + /** + * Provides a partial `Knex.Config`• database name override for a given plugin. + * + * @param pluginId - Target plugin to get database name override + * @returns Partial `Knex.Config` with database name override + */ + private getDatabaseOverrides(pluginId: string): Knex.Config { + const databaseName = this.getDatabaseName(pluginId); + return databaseName + ? createNameOverride(this.getClientType(pluginId).client, databaseName) + : {}; + } +} diff --git a/packages/backend-common/src/database/connectors/postgres.test.ts b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.test.ts similarity index 100% rename from packages/backend-common/src/database/connectors/postgres.test.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/postgres.test.ts index 39c9af5ef3..1e07984967 100644 --- a/packages/backend-common/src/database/connectors/postgres.test.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.test.ts @@ -16,8 +16,8 @@ import { Config, ConfigReader } from '@backstage/config'; import { - createPgDatabaseClient, buildPgDatabaseConfig, + createPgDatabaseClient, getPgConnectionConfig, parsePgConnectionString, } from './postgres'; diff --git a/packages/backend-defaults/src/entrypoints/database/connectors/postgres.ts b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.ts new file mode 100644 index 0000000000..b81bfd5b50 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.ts @@ -0,0 +1,542 @@ +/* + * 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 { + LifecycleService, + PluginMetadataService, +} from '@backstage/backend-plugin-api'; +import { Config, ConfigReader } from '@backstage/config'; +import { ForwardedError, InputError } from '@backstage/errors'; +import { JsonObject } from '@backstage/types'; +import knexFactory, { Knex } from 'knex'; +import { merge, omit } from 'lodash'; +import limiterFactory from 'p-limit'; +import { Client } from 'pg'; +import { Connector, DatabaseConnector } from '../types'; +import defaultNameOverride from './defaultNameOverride'; +import defaultSchemaOverride from './defaultSchemaOverride'; +import { mergeDatabaseConfig } from './mergeDatabaseConfig'; + +// Limits the number of concurrent DDL operations to 1 +const ddlLimiter = limiterFactory(1); + +/** + * Creates a knex postgres database connection + * + * @param dbConfig - The database config + * @param overrides - Additional options to merge with the config + */ +export function createPgDatabaseClient( + dbConfig: Config, + overrides?: Knex.Config, +) { + const knexConfig = buildPgDatabaseConfig(dbConfig, overrides); + const database = knexFactory(knexConfig); + + const role = dbConfig.getOptionalString('role'); + + if (role) { + database.client.pool.on( + 'createSuccess', + async (_event: number, pgClient: Client) => { + await pgClient.query(`SET ROLE ${role}`); + }, + ); + } + return database; +} + +/** + * Builds a knex postgres database connection + * + * @param dbConfig - The database config + * @param overrides - Additional options to merge with the config + */ +export function buildPgDatabaseConfig( + dbConfig: Config, + overrides?: Knex.Config, +) { + return mergeDatabaseConfig( + dbConfig.get(), + { + connection: getPgConnectionConfig(dbConfig, !!overrides), + useNullAsDefault: true, + }, + overrides, + ); +} + +/** + * Gets the postgres connection config + * + * @param dbConfig - The database config + * @param parseConnectionString - Flag to explicitly control connection string parsing + */ +export function getPgConnectionConfig( + dbConfig: Config, + parseConnectionString?: boolean, +): Knex.PgConnectionConfig | string { + const connection = dbConfig.get('connection') as any; + const isConnectionString = + typeof connection === 'string' || connection instanceof String; + const autoParse = typeof parseConnectionString !== 'boolean'; + + const shouldParseConnectionString = autoParse + ? isConnectionString + : parseConnectionString && isConnectionString; + + return shouldParseConnectionString + ? parsePgConnectionString(connection as string) + : connection; +} + +/** + * Parses a connection string using pg-connection-string + * + * @param connectionString - The postgres connection string + */ +export function parsePgConnectionString(connectionString: string) { + const parse = requirePgConnectionString(); + return parse(connectionString); +} + +function requirePgConnectionString() { + try { + return require('pg-connection-string').parse; + } catch (e) { + throw new ForwardedError("Postgres: Install 'pg-connection-string'", e); + } +} + +/** + * Creates the missing Postgres database if it does not exist + * + * @param dbConfig - The database config + * @param databases - The name of the databases to create + */ +export async function ensurePgDatabaseExists( + dbConfig: Config, + ...databases: Array +) { + const admin = createPgDatabaseClient(dbConfig, { + connection: { + database: 'postgres', + }, + pool: { + min: 0, + acquireTimeoutMillis: 10000, + }, + }); + + try { + const ensureDatabase = async (database: string) => { + const result = await admin + .from('pg_database') + .where('datname', database) + .count>(); + + if (parseInt(result[0].count, 10) > 0) { + return; + } + + await admin.raw(`CREATE DATABASE ??`, [database]); + }; + + await Promise.all( + databases.map(async database => { + // For initial setup we use a smaller timeout but several retries. Given that this + // is a separate connection pool we should never really run into issues with connection + // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency. + let lastErr: Error | undefined = undefined; + for (let i = 0; i < 3; i++) { + try { + return await ddlLimiter(() => ensureDatabase(database)); + } catch (err) { + lastErr = err; + } + await new Promise(resolve => setTimeout(resolve, 100)); + } + throw lastErr; + }), + ); + } finally { + await admin.destroy(); + } +} + +/** + * Creates the missing Postgres schema if it does not exist + * + * @param dbConfig - The database config + * @param schemas - The name of the schemas to create + */ +export async function ensurePgSchemaExists( + dbConfig: Config, + ...schemas: Array +): Promise { + const admin = createPgDatabaseClient(dbConfig); + const role = dbConfig.getOptionalString('role'); + + try { + const ensureSchema = async (database: string) => { + if (role) { + await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [ + database, + role, + ]); + } else { + await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]); + } + }; + + await Promise.all( + schemas.map(database => ddlLimiter(() => ensureSchema(database))), + ); + } finally { + await admin.destroy(); + } +} + +/** + * Drops the Postgres databases. + * + * @param dbConfig - The database config + * @param databases - The name of the databases to drop + */ +export async function dropPgDatabase( + dbConfig: Config, + ...databases: Array +) { + const admin = createPgDatabaseClient(dbConfig); + try { + await Promise.all( + databases.map(async database => { + await ddlLimiter(() => admin.raw(`DROP DATABASE ??`, [database])); + }), + ); + } finally { + await admin.destroy(); + } +} + +export const pgConnector: DatabaseConnector = Object.freeze({ + createClient: createPgDatabaseClient, + ensureDatabaseExists: ensurePgDatabaseExists, + ensureSchemaExists: ensurePgSchemaExists, + createNameOverride: defaultNameOverride, + createSchemaOverride: defaultSchemaOverride, + parseConnectionString: parsePgConnectionString, + dropDatabase: dropPgDatabase, +}); + +/** + * Provides a config lookup path for a plugin's config block. + */ +function pluginPath(pluginId: string): string { + return `plugin.${pluginId}`; +} + +function normalizeConnection( + connection: Knex.StaticConnectionConfig | JsonObject | string | undefined, + client: string, +): Partial { + if (typeof connection === 'undefined' || connection === null) { + return {}; + } + + return typeof connection === 'string' || connection instanceof String + ? pgConnector.parseConnectionString(connection as string, client) + : connection; +} + +function createSchemaOverride( + client: string, + name: string, +): Partial { + try { + return pgConnector.createSchemaOverride?.(name); + } catch (e) { + throw new InputError( + `Unable to create database schema override for '${client}' connector`, + e, + ); + } +} + +function createNameOverride( + client: string, + name: string, +): Partial { + try { + return pgConnector.createNameOverride(name); + } catch (e) { + throw new InputError( + `Unable to create database name override for '${client}' connector`, + e, + ); + } +} + +export class PgConnector implements Connector { + constructor( + private readonly config: Config, + private readonly prefix: string, + ) {} + + async getClient( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): Promise { + const pluginConfig = new ConfigReader( + this.getConfigForPlugin(pluginId) as JsonObject, + ); + + const databaseName = this.getDatabaseName(pluginId); + if (databaseName && this.getEnsureExistsConfig(pluginId)) { + try { + await pgConnector.ensureDatabaseExists!(pluginConfig, databaseName); + } catch (error) { + throw new Error( + `Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`, + ); + } + } + + let schemaOverrides; + if (this.getPluginDivisionModeConfig() === 'schema') { + schemaOverrides = this.getSchemaOverrides(pluginId); + if ( + this.getEnsureSchemaExistsConfig(pluginId) || + this.getEnsureExistsConfig(pluginId) + ) { + try { + await pgConnector.ensureSchemaExists!(pluginConfig, pluginId); + } catch (error) { + throw new Error( + `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`, + ); + } + } + } + + const databaseClientOverrides = mergeDatabaseConfig( + {}, + this.getDatabaseOverrides(pluginId), + schemaOverrides, + ); + + const client = pgConnector.createClient( + pluginConfig, + databaseClientOverrides, + deps, + ); + + return client; + } + + async dropDatabase(...databaseNames: string[]): Promise { + return await dropPgDatabase(this.config, ...databaseNames); + } + + /** + * Provides the canonical database name for a given plugin. + * + * This method provides the effective database name which is determined using global + * and plugin specific database config. If no explicit database name is configured + * and `pluginDivisionMode` is not `schema`, this method will provide a generated name + * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is + * `schema`, it will fallback to using the default database for the knex instance. + * + * @param pluginId - Lookup the database name for given plugin + * @returns String representing the plugin's database name + */ + private getDatabaseName(pluginId: string): string | undefined { + const connection = this.getConnectionConfig(pluginId); + + const databaseName = (connection as Knex.ConnectionConfig)?.database; + + // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied or fallback to default knex database + if (this.getPluginDivisionModeConfig() === 'schema') { + return databaseName; + } + + // all other supported databases should fallback to an auto-prefixed name + return databaseName ?? `${this.prefix}${pluginId}`; + } + + /** + * Provides the client type which should be used for a given plugin. + * + * The client type is determined by plugin specific config if present. + * Otherwise the base client is used as the fallback. + * + * @param pluginId - Plugin to get the client type for + * @returns Object with client type returned as `client` and boolean + * representing whether or not the client was overridden as + * `overridden` + */ + private getClientType(pluginId: string): { + client: string; + overridden: boolean; + } { + const pluginClient = this.config.getOptionalString( + `${pluginPath(pluginId)}.client`, + ); + + const baseClient = this.config.getString('client'); + const client = pluginClient ?? baseClient; + return { + client, + overridden: client !== baseClient, + }; + } + + private getRoleConfig(pluginId: string): string | undefined { + return ( + this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ?? + this.config.getOptionalString('role') + ); + } + + /** + * Provides the knexConfig which should be used for a given plugin. + * + * @param pluginId - Plugin to get the knexConfig for + * @returns The merged knexConfig value or undefined if it isn't specified + */ + private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined { + const pluginConfig = this.config + .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`) + ?.get(); + + const baseConfig = this.config + .getOptionalConfig('knexConfig') + ?.get(); + + return merge(baseConfig, pluginConfig); + } + + private getEnsureExistsConfig(pluginId: string): boolean { + const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true; + return ( + this.config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ?? + baseConfig + ); + } + + private getEnsureSchemaExistsConfig(pluginId: string): boolean { + const baseConfig = + this.config.getOptionalBoolean('ensureSchemaExists') ?? false; + return ( + this.config.getOptionalBoolean( + `${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`, + ) ?? baseConfig + ); + } + + private getPluginDivisionModeConfig(): string { + return this.config.getOptionalString('pluginDivisionMode') ?? 'database'; + } + + /** + * Provides a Knex connection plugin config by combining base and plugin + * config. + * + * This method provides a baseConfig for a plugin database connector. If the + * client type has not been overridden, the global connection config will be + * included with plugin specific config as the base. Values from the plugin + * connection take precedence over the base. Base database name is omitted + * unless `pluginDivisionMode` is set to `schema`. + */ + private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig { + const { client, overridden } = this.getClientType(pluginId); + + let baseConnection = normalizeConnection( + this.config.get('connection'), + this.config.getString('client'), + ); + + // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The + // `database` property from the base connection is omitted unless `pluginDivisionMode` + // is set to `schema`. + if (this.getPluginDivisionModeConfig() !== 'schema') { + baseConnection = omit(baseConnection, 'database'); + } + + // get and normalize optional plugin specific database connection + const connection = normalizeConnection( + this.config.getOptional(`${pluginPath(pluginId)}.connection`), + client, + ); + + ( + baseConnection as Knex.PgConnectionConfig + ).application_name ||= `backstage_plugin_${pluginId}`; + + return { + // include base connection if client type has not been overridden + ...(overridden ? {} : baseConnection), + ...connection, + } as Knex.StaticConnectionConfig; + } + + /** + * Provides a Knex database config for a given plugin. + * + * This method provides a Knex configuration object along with the plugin's + * client type. + * + * @param pluginId - The plugin that the database config should correspond with + */ + private getConfigForPlugin(pluginId: string): Knex.Config { + const { client } = this.getClientType(pluginId); + const role = this.getRoleConfig(pluginId); + + return { + ...this.getAdditionalKnexConfig(pluginId), + client, + connection: this.getConnectionConfig(pluginId), + ...(role && { role }), + }; + } + + /** + * Provides a partial `Knex.Config` database schema override for a given + * plugin. + * + * @param pluginId - Target plugin to get database schema override + * @returns Partial `Knex.Config` with database schema override + */ + private getSchemaOverrides(pluginId: string): Knex.Config | undefined { + return createSchemaOverride(this.getClientType(pluginId).client, pluginId); + } + + /** + * Provides a partial `Knex.Config`• database name override for a given plugin. + * + * @param pluginId - Target plugin to get database name override + * @returns Partial `Knex.Config` with database name override + */ + private getDatabaseOverrides(pluginId: string): Knex.Config { + const databaseName = this.getDatabaseName(pluginId); + return databaseName + ? createNameOverride(this.getClientType(pluginId).client, databaseName) + : {}; + } +} diff --git a/packages/backend-common/src/database/connectors/sqlite3.test.ts b/packages/backend-defaults/src/entrypoints/database/connectors/sqlite3.test.ts similarity index 100% rename from packages/backend-common/src/database/connectors/sqlite3.test.ts rename to packages/backend-defaults/src/entrypoints/database/connectors/sqlite3.test.ts diff --git a/packages/backend-defaults/src/entrypoints/database/connectors/sqlite3.ts b/packages/backend-defaults/src/entrypoints/database/connectors/sqlite3.ts new file mode 100644 index 0000000000..46ff756854 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/connectors/sqlite3.ts @@ -0,0 +1,411 @@ +/* + * 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 { DevDataStore } from '@backstage/backend-dev-utils'; +import { + LifecycleService, + PluginMetadataService, +} from '@backstage/backend-plugin-api'; +import { Config, ConfigReader } from '@backstage/config'; +import { InputError } from '@backstage/errors'; +import { JsonObject } from '@backstage/types'; +import { ensureDirSync } from 'fs-extra'; +import knexFactory, { Knex } from 'knex'; +import { merge, omit } from 'lodash'; +import path from 'path'; +import { Connector, DatabaseConnector } from '../types'; +import { mergeDatabaseConfig } from './mergeDatabaseConfig'; + +/** + * Creates a knex SQLite3 database connection + * + * @param dbConfig - The database config + * @param overrides - Additional options to merge with the config + */ +export function createSqliteDatabaseClient( + dbConfig: Config, + overrides?: Knex.Config, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, +) { + const knexConfig = buildSqliteDatabaseConfig(dbConfig, overrides); + const connConfig = knexConfig.connection as Knex.Sqlite3ConnectionConfig; + + const filename = connConfig.filename ?? ':memory:'; + + // If storage on disk is used, ensure that the directory exists + if (filename !== ':memory:') { + const directory = path.dirname(filename); + ensureDirSync(directory); + } + + let database: Knex; + + if (deps && filename === ':memory:') { + // The dev store is used during watch mode to store and restore the database + // across reloads. It is only available when running the backend through + // `backstage-cli package start`. + const devStore = DevDataStore.get(); + + if (devStore) { + const dataKey = `sqlite3-db-${deps.pluginMetadata.getId()}`; + + const connectionLoader = async () => { + // If seed data is available, use it tconnectionLoader restore the database + const { data: seedData } = await devStore.load(dataKey); + + return { + ...(knexConfig.connection as Knex.Sqlite3ConnectionConfig), + filename: seedData ?? ':memory:', + }; + }; + + database = knexFactory({ + ...knexConfig, + connection: Object.assign(connectionLoader, { + // This is a workaround for the knex SQLite driver always warning when using a config loader + filename: ':memory:', + }), + }); + + // If the dev store is available we save the database state on shutdown + deps.lifecycle.addShutdownHook(async () => { + const connection = await database.client.acquireConnection(); + const data = connection.serialize(); + await devStore.save(dataKey, data); + }); + } else { + database = knexFactory(knexConfig); + } + } else { + database = knexFactory(knexConfig); + } + + database.client.pool.on('createSuccess', (_eventId: any, resource: any) => { + resource.run('PRAGMA foreign_keys = ON', () => {}); + }); + + return database; +} + +/** + * Builds a knex SQLite3 connection config + * + * @param dbConfig - The database config + * @param overrides - Additional options to merge with the config + */ +export function buildSqliteDatabaseConfig( + dbConfig: Config, + overrides?: Knex.Config, +): Knex.Config { + const baseConfig = dbConfig.get(); + + // Normalize config to always contain a connection object + if (typeof baseConfig.connection === 'string') { + baseConfig.connection = { filename: baseConfig.connection }; + } + if (overrides && typeof overrides.connection === 'string') { + overrides.connection = { filename: overrides.connection }; + } + + const config: Knex.Config = mergeDatabaseConfig( + { + connection: {}, + }, + baseConfig, + { + useNullAsDefault: true, + }, + overrides, + ); + + return config; +} + +/** + * Provides a partial knex SQLite3 config to override database name. + */ +export function createSqliteNameOverride(name: string): Partial { + return { + connection: parseSqliteConnectionString(name), + }; +} + +/** + * Produces a partial knex SQLite3 connection config with database name. + */ +export function parseSqliteConnectionString( + name: string, +): Knex.Sqlite3ConnectionConfig { + return { + filename: name, + }; +} + +/** + * SQLite3 database connector. + * + * Exposes database connector functionality via an immutable object. + */ +export const sqliteConnector: DatabaseConnector = Object.freeze({ + createClient: createSqliteDatabaseClient, + createNameOverride: createSqliteNameOverride, + parseConnectionString: parseSqliteConnectionString, +}); + +/** + * Provides a config lookup path for a plugin's config block. + */ +function pluginPath(pluginId: string): string { + return `plugin.${pluginId}`; +} + +function normalizeConnection( + connection: Knex.StaticConnectionConfig | JsonObject | string | undefined, + client: string, +): Partial { + if (typeof connection === 'undefined' || connection === null) { + return {}; + } + + return typeof connection === 'string' || connection instanceof String + ? sqliteConnector.parseConnectionString(connection as string, client) + : connection; +} + +function createNameOverride( + client: string, + name: string, +): Partial { + try { + return sqliteConnector.createNameOverride(name); + } catch (e) { + throw new InputError( + `Unable to create database name override for '${client}' connector`, + e, + ); + } +} + +export class Sqlite3Connector implements Connector { + constructor(private readonly config: Config) {} + + async getClient( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): Promise { + const pluginConfig = new ConfigReader( + this.getConfigForPlugin(pluginId) as JsonObject, + ); + + const pluginDivisionMode = this.getPluginDivisionModeConfig(); + if (pluginDivisionMode !== 'database') { + throw new Error( + `The SQLite driver does not suppoert plugin division mode '${pluginDivisionMode}'`, + ); + } + + const databaseClientOverrides = mergeDatabaseConfig( + {}, + this.getDatabaseOverrides(pluginId), + ); + + const client = sqliteConnector.createClient( + pluginConfig, + databaseClientOverrides, + deps, + ); + + return client; + } + + async dropDatabase(..._databaseNames: string[]): Promise { + // do nothing + } + + /** + * Provides the canonical database name for a given plugin. + * + * This method provides the effective database name which is determined using global + * and plugin specific database config. If no explicit database name is configured + * and `pluginDivisionMode` is not `schema`, this method will provide a generated name + * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is + * `schema`, it will fallback to using the default database for the knex instance. + * + * @param pluginId - Lookup the database name for given plugin + * @returns String representing the plugin's database name + */ + private getDatabaseName(pluginId: string): string | undefined { + const connection = this.getConnectionConfig(pluginId); + + const sqliteFilename: string | undefined = ( + connection as Knex.Sqlite3ConnectionConfig + ).filename; + + if (sqliteFilename === ':memory:') { + return sqliteFilename; + } + + const sqliteDirectory = + (connection as { directory?: string }).directory ?? '.'; + + return path.join(sqliteDirectory, sqliteFilename ?? `${pluginId}.sqlite`); + } + + /** + * Provides the client type which should be used for a given plugin. + * + * The client type is determined by plugin specific config if present. + * Otherwise the base client is used as the fallback. + * + * @param pluginId - Plugin to get the client type for + * @returns Object with client type returned as `client` and boolean + * representing whether or not the client was overridden as + * `overridden` + */ + private getClientType(pluginId: string): { + client: string; + overridden: boolean; + } { + const pluginClient = this.config.getOptionalString( + `${pluginPath(pluginId)}.client`, + ); + + const baseClient = this.config.getString('client'); + const client = pluginClient ?? baseClient; + return { + client, + overridden: client !== baseClient, + }; + } + + private getRoleConfig(pluginId: string): string | undefined { + return ( + this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ?? + this.config.getOptionalString('role') + ); + } + + /** + * Provides the knexConfig which should be used for a given plugin. + * + * @param pluginId - Plugin to get the knexConfig for + * @returns The merged knexConfig value or undefined if it isn't specified + */ + private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined { + const pluginConfig = this.config + .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`) + ?.get(); + + const baseConfig = this.config + .getOptionalConfig('knexConfig') + ?.get(); + + return merge(baseConfig, pluginConfig); + } + + private getPluginDivisionModeConfig(): string { + return this.config.getOptionalString('pluginDivisionMode') ?? 'database'; + } + + /** + * Provides a Knex connection plugin config by combining base and plugin + * config. + * + * This method provides a baseConfig for a plugin database connector. If the + * client type has not been overridden, the global connection config will be + * included with plugin specific config as the base. Values from the plugin + * connection take precedence over the base. Base database name is omitted for + * all supported databases excluding SQLite unless `pluginDivisionMode` is set + * to `schema`. + */ + private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig { + const { client, overridden } = this.getClientType(pluginId); + + let baseConnection = normalizeConnection( + this.config.get('connection'), + this.config.getString('client'), + ); + + if ( + client.includes('sqlite3') && + 'filename' in baseConnection && + baseConnection.filename !== ':memory:' + ) { + throw new Error( + '`connection.filename` is not supported for the base sqlite connection. Prefer `connection.directory` or provide a filename for the plugin connection instead.', + ); + } + + // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The + // `database` property from the base connection is omitted unless `pluginDivisionMode` + // is set to `schema`. SQLite3's `filename` property is an exception as this is used as a + // directory elsewhere so we preserve `filename`. + if (this.getPluginDivisionModeConfig() !== 'schema') { + baseConnection = omit(baseConnection, 'database'); + } + + // get and normalize optional plugin specific database connection + const connection = normalizeConnection( + this.config.getOptional(`${pluginPath(pluginId)}.connection`), + client, + ); + + return { + // include base connection if client type has not been overridden + ...(overridden ? {} : baseConnection), + ...connection, + } as Knex.StaticConnectionConfig; + } + + /** + * Provides a Knex database config for a given plugin. + * + * This method provides a Knex configuration object along with the plugin's + * client type. + * + * @param pluginId - The plugin that the database config should correspond with + */ + private getConfigForPlugin(pluginId: string): Knex.Config { + const { client } = this.getClientType(pluginId); + const role = this.getRoleConfig(pluginId); + + return { + ...this.getAdditionalKnexConfig(pluginId), + client, + connection: this.getConnectionConfig(pluginId), + ...(role && { role }), + }; + } + + /** + * Provides a partial `Knex.Config`• database name override for a given plugin. + * + * @param pluginId - Target plugin to get database name override + * @returns Partial `Knex.Config` with database name override + */ + private getDatabaseOverrides(pluginId: string): Knex.Config { + const databaseName = this.getDatabaseName(pluginId); + return databaseName + ? createNameOverride(this.getClientType(pluginId).client, databaseName) + : {}; + } +} diff --git a/packages/backend-defaults/src/entrypoints/database/databaseServiceFactory.ts b/packages/backend-defaults/src/entrypoints/database/databaseServiceFactory.ts new file mode 100644 index 0000000000..12e4e569bd --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/databaseServiceFactory.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DatabaseManager } from '@backstage/backend-common'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { ConfigReader } from '@backstage/config'; + +/** + * @public + */ +export const databaseServiceFactory = createServiceFactory({ + service: coreServices.database, + deps: { + config: coreServices.rootConfig, + lifecycle: coreServices.lifecycle, + pluginMetadata: coreServices.pluginMetadata, + }, + async createRootContext({ config }) { + return config.getOptional('backend.database') + ? DatabaseManager.fromConfig(config) + : DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + }, + async factory({ pluginMetadata, lifecycle }, databaseManager) { + return databaseManager.forPlugin(pluginMetadata.getId(), { + pluginMetadata, + lifecycle, + }); + }, +}); diff --git a/packages/backend-defaults/src/entrypoints/database/index.ts b/packages/backend-defaults/src/entrypoints/database/index.ts new file mode 100644 index 0000000000..7d6221b856 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { databaseServiceFactory } from './databaseServiceFactory'; +export { + DatabaseManager, + type DatabaseManagerOptions, + type LegacyRootDatabaseService, + dropDatabase, +} from './DatabaseManager'; diff --git a/packages/backend-defaults/src/entrypoints/database/types.ts b/packages/backend-defaults/src/entrypoints/database/types.ts new file mode 100644 index 0000000000..a9cceaa1f9 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/database/types.ts @@ -0,0 +1,100 @@ +/* + * 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 { + LifecycleService, + PluginMetadataService, +} from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { Knex } from 'knex'; + +export type { DatabaseService as PluginDatabaseManager } from '@backstage/backend-plugin-api'; + +/** + * Manages an underlying Knex database driver. + */ +export interface DatabaseConnector { + /** + * Provides an instance of a knex database connector. + */ + createClient( + dbConfig: Config, + overrides?: Partial, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): Knex; + + /** + * Provides a partial knex config sufficient to override a database name. + */ + createNameOverride(name: string): Partial; + + /** + * Provides a partial knex config sufficient to override a PostgreSQL schema + * name within utilizing the `searchPath` knex configuration. + */ + createSchemaOverride?(name: string): Partial; + + /** + * Produces a knex connection config object representing a database connection + * string. + */ + parseConnectionString( + connectionString: string, + client?: string, + ): Knex.StaticConnectionConfig; + + /** + * Performs a side-effect to ensure database names passed in are present. + * + * Calling this function on databases which already exist should do nothing. + * Missing databases should be created if needed. + */ + ensureDatabaseExists?( + dbConfig: Config, + ...databases: Array + ): Promise; + + /** + * Performs a side-effect to ensure schema names passed in are present. + * + * Calling this function on schemas which already exist should do nothing. + * Missing schemas should be created if needed. + */ + ensureSchemaExists?( + dbConfig: Config, + ...schemas: Array + ): Promise; + + /** + * Deletes databases. + */ + dropDatabase?(dbConfig: Config, ...databases: Array): Promise; +} + +export interface Connector { + getClient( + pluginId: string, + deps?: { + lifecycle: LifecycleService; + pluginMetadata: PluginMetadataService; + }, + ): Promise; + + dropDatabase(...databaseNames: string[]): Promise; +} diff --git a/packages/backend-defaults/src/entrypoints/discovery/HostDiscovery.test.ts b/packages/backend-defaults/src/entrypoints/discovery/HostDiscovery.test.ts new file mode 100644 index 0000000000..4e6aff5853 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/discovery/HostDiscovery.test.ts @@ -0,0 +1,257 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { HostDiscovery } from './HostDiscovery'; + +describe('HostDiscovery', () => { + it('is created from config', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + listen: { port: 80, host: 'localhost' }, + }, + }), + ); + + await expect(discovery.getBaseUrl('catalog')).resolves.toBe( + 'http://localhost:80/api/catalog', + ); + await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe( + 'http://localhost:40/api/catalog', + ); + }); + + it('strips trailing slashes in config', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40//', + listen: { port: 80, host: 'localhost' }, + }, + }), + ); + + await expect(discovery.getBaseUrl('catalog')).resolves.toBe( + 'http://localhost:80/api/catalog', + ); + await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe( + 'http://localhost:40/api/catalog', + ); + }); + + it('can configure the base path', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + listen: { port: 80, host: 'localhost' }, + }, + }), + { basePath: '/service' }, + ); + + await expect(discovery.getBaseUrl('catalog')).resolves.toBe( + 'http://localhost:80/service/catalog', + ); + await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe( + 'http://localhost:40/service/catalog', + ); + }); + + it.each([ + [{ listen: ':80' }, 'http://localhost:80'], + [{ listen: ':40', https: true }, 'https://localhost:40'], + [{ listen: '127.0.0.1:80' }, 'http://127.0.0.1:80'], + [{ listen: '127.0.0.1:80', https: true }, 'https://127.0.0.1:80'], + [{ listen: '0.0.0.0:40' }, 'http://127.0.0.1:40'], + [{ listen: { port: 80 } }, 'http://localhost:80'], + [{ listen: { port: 8000 } }, 'http://localhost:8000'], + [{ listen: { port: 80, host: '0.0.0.0' } }, 'http://127.0.0.1:80'], + [{ listen: { port: 80, host: '::' } }, 'http://localhost:80'], + [{ listen: { port: 80, host: '::1' } }, 'http://[::1]:80'], + [{ listen: { port: 90, host: '::2' }, https: true }, 'https://[::2]:90'], + ])('resolves internal baseUrl for %j as %s', async (config, expected) => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + ...config, + }, + }), + ); + + await expect(discovery.getBaseUrl('catalog')).resolves.toBe( + `${expected}/api/catalog`, + ); + }); + + it('uses plugin specific targets from config if provided', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + listen: { port: 80, host: 'localhost' }, + }, + discovery: { + endpoints: [ + { + target: { + internal: 'http://catalog-backend-internal:8080/api/catalog', + external: 'http://catalog-backend-external:8080/api/catalog', + }, + plugins: ['catalog'], + }, + ], + }, + }), + ); + + await expect(discovery.getBaseUrl('catalog')).resolves.toBe( + 'http://catalog-backend-internal:8080/api/catalog', + ); + await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe( + 'http://catalog-backend-external:8080/api/catalog', + ); + }); + + it('uses a single target for internal and external for a plugin', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + listen: { port: 80, host: 'localhost' }, + }, + discovery: { + endpoints: [ + { + target: 'http://catalog-backend:8080/api/catalog', + plugins: ['catalog'], + }, + ], + }, + }), + ); + + await expect(discovery.getBaseUrl('catalog')).resolves.toBe( + 'http://catalog-backend:8080/api/catalog', + ); + await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe( + 'http://catalog-backend:8080/api/catalog', + ); + }); + + it('defaults to the backend baseUrl when there is not an endpoint for a plugin', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + listen: { port: 80, host: 'localhost' }, + }, + discovery: { + endpoints: [ + { + target: 'http://catalog-backend:8080/api/catalog', + plugins: ['catalog'], + }, + ], + }, + }), + ); + + await expect(discovery.getBaseUrl('scaffolder')).resolves.toBe( + 'http://localhost:80/api/scaffolder', + ); + await expect(discovery.getExternalBaseUrl('scaffolder')).resolves.toBe( + 'http://localhost:40/api/scaffolder', + ); + }); + + it('replaces {{pluginId}} or {{ pluginId }} in the target', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + listen: { port: 80, host: 'localhost' }, + }, + discovery: { + endpoints: [ + { + target: 'http://common-backend:8080/api/{{pluginId}}', + plugins: ['catalog', 'docs'], + }, + { + target: { + internal: 'http://scaffolder-internal:8080/api/{{ pluginId }}', + external: 'http://scaffolder-external:8080/api/{{ pluginId }}', + }, + plugins: ['scaffolder'], + }, + ], + }, + }), + ); + + await expect(discovery.getBaseUrl('catalog')).resolves.toBe( + 'http://common-backend:8080/api/catalog', + ); + await expect(discovery.getExternalBaseUrl('catalog')).resolves.toBe( + 'http://common-backend:8080/api/catalog', + ); + await expect(discovery.getBaseUrl('docs')).resolves.toBe( + 'http://common-backend:8080/api/docs', + ); + await expect(discovery.getExternalBaseUrl('docs')).resolves.toBe( + 'http://common-backend:8080/api/docs', + ); + await expect(discovery.getBaseUrl('scaffolder')).resolves.toBe( + 'http://scaffolder-internal:8080/api/scaffolder', + ); + await expect(discovery.getExternalBaseUrl('scaffolder')).resolves.toBe( + 'http://scaffolder-external:8080/api/scaffolder', + ); + }); + + it('encodes the pluginId', async () => { + const discovery = HostDiscovery.fromConfig( + new ConfigReader({ + backend: { + baseUrl: 'http://localhost:40', + listen: { port: 80, host: 'localhost' }, + }, + discovery: { + endpoints: [ + { + target: 'http://common-backend:8080/api/{{pluginId}}', + plugins: ['plugin/beta'], + }, + ], + }, + }), + ); + + await expect(discovery.getBaseUrl('plugin/beta')).resolves.toBe( + 'http://common-backend:8080/api/plugin%2Fbeta', + ); + await expect(discovery.getBaseUrl('plugin/alpha')).resolves.toBe( + 'http://localhost:80/api/plugin%2Falpha', + ); + await expect(discovery.getExternalBaseUrl('plugin/alpha')).resolves.toBe( + 'http://localhost:40/api/plugin%2Falpha', + ); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/discovery/HostDiscovery.ts b/packages/backend-defaults/src/entrypoints/discovery/HostDiscovery.ts new file mode 100644 index 0000000000..180c8706d5 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/discovery/HostDiscovery.ts @@ -0,0 +1,132 @@ +/* + * 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 { Config } from '@backstage/config'; +import { readHttpServerOptions } from '@backstage/backend-app-api'; +import { DiscoveryService } from '@backstage/backend-plugin-api'; + +type Target = string | { internal: string; external: string }; + +/** + * HostDiscovery is a basic PluginEndpointDiscovery implementation + * that can handle plugins that are hosted in a single or multiple deployments. + * + * The deployment may be scaled horizontally, as long as the external URL + * is the same for all instances. However, internal URLs will always be + * resolved to the same host, so there won't be any balancing of internal traffic. + * + * @public + */ +export class HostDiscovery implements DiscoveryService { + /** + * Creates a new HostDiscovery discovery instance by reading + * from the `backend` config section, specifically the `.baseUrl` for + * discovering the external URL, and the `.listen` and `.https` config + * for the internal one. + * + * Can be overridden in config by providing a target and corresponding plugins in `discovery.endpoints`. + * eg. + * ```yaml + * discovery: + * endpoints: + * - target: https://internal.example.com/internal-catalog + * plugins: [catalog] + * - target: https://internal.example.com/secure/api/{{pluginId}} + * plugins: [auth, permission] + * - target: + * internal: https://internal.example.com/search + * external: https://example.com/search + * plugins: [search] + * ``` + * + * The basePath defaults to `/api`, meaning the default full internal + * path for the `catalog` plugin will be `http://localhost:7007/api/catalog`. + */ + static fromConfig(config: Config, options?: { basePath?: string }) { + const basePath = options?.basePath ?? '/api'; + const externalBaseUrl = config + .getString('backend.baseUrl') + .replace(/\/+$/, ''); + + const { + listen: { host: listenHost = '::', port: listenPort }, + } = readHttpServerOptions(config.getConfig('backend')); + const protocol = config.has('backend.https') ? 'https' : 'http'; + + // Translate bind-all to localhost, and support IPv6 + let host = listenHost; + if (host === '::' || host === '') { + // We use localhost instead of ::1, since IPv6-compatible systems should default + // to using IPv6 when they see localhost, but if the system doesn't support IPv6 + // things will still work. + host = 'localhost'; + } else if (host === '0.0.0.0') { + host = '127.0.0.1'; + } + if (host.includes(':')) { + host = `[${host}]`; + } + + const internalBaseUrl = `${protocol}://${host}:${listenPort}`; + + return new HostDiscovery( + internalBaseUrl + basePath, + externalBaseUrl + basePath, + config.getOptionalConfig('discovery'), + ); + } + + private constructor( + private readonly internalBaseUrl: string, + private readonly externalBaseUrl: string, + private readonly discoveryConfig: Config | undefined, + ) {} + + private getTargetFromConfig(pluginId: string, type: 'internal' | 'external') { + const endpoints = this.discoveryConfig?.getOptionalConfigArray('endpoints'); + + const target = endpoints + ?.find(endpoint => endpoint.getStringArray('plugins').includes(pluginId)) + ?.get('target'); + + if (!target) { + const baseUrl = + type === 'external' ? this.externalBaseUrl : this.internalBaseUrl; + + return `${baseUrl}/${encodeURIComponent(pluginId)}`; + } + + if (typeof target === 'string') { + return target.replace( + /\{\{\s*pluginId\s*\}\}/g, + encodeURIComponent(pluginId), + ); + } + + return target[type].replace( + /\{\{\s*pluginId\s*\}\}/g, + encodeURIComponent(pluginId), + ); + } + + async getBaseUrl(pluginId: string): Promise { + return this.getTargetFromConfig(pluginId, 'internal'); + } + + async getExternalBaseUrl(pluginId: string): Promise { + return this.getTargetFromConfig(pluginId, 'external'); + } +} diff --git a/packages/theme/src/unified/MuiClassNameSetup.ts b/packages/backend-defaults/src/entrypoints/discovery/discoveryServiceFactory.ts similarity index 61% rename from packages/theme/src/unified/MuiClassNameSetup.ts rename to packages/backend-defaults/src/entrypoints/discovery/discoveryServiceFactory.ts index 5d7e0b26fe..bfc5a6a489 100644 --- a/packages/theme/src/unified/MuiClassNameSetup.ts +++ b/packages/backend-defaults/src/entrypoints/discovery/discoveryServiceFactory.ts @@ -14,11 +14,19 @@ * limitations under the License. */ -import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { HostDiscovery } from './HostDiscovery'; -/** - * This API is introduced in @mui/material (v5.0.5) as a replacement of deprecated createGenerateClassName & only affects v5 Material UI components from `@mui/*` - */ -ClassNameGenerator.configure(componentName => { - return `v5-${componentName}`; +/** @public */ +export const discoveryServiceFactory = createServiceFactory({ + service: coreServices.discovery, + deps: { + config: coreServices.rootConfig, + }, + async factory({ config }) { + return HostDiscovery.fromConfig(config); + }, }); diff --git a/packages/backend-defaults/src/entrypoints/discovery/index.ts b/packages/backend-defaults/src/entrypoints/discovery/index.ts new file mode 100644 index 0000000000..ee4851271a --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/discovery/index.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 { discoveryServiceFactory } from './discoveryServiceFactory'; +export { HostDiscovery } from './HostDiscovery'; diff --git a/packages/backend-defaults/src/entrypoints/lifecycle/index.ts b/packages/backend-defaults/src/entrypoints/lifecycle/index.ts new file mode 100644 index 0000000000..8dac4c26b4 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/lifecycle/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 { lifecycleServiceFactory } from './lifecycleServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/lifecycle/lifecycleServiceFactory.ts b/packages/backend-defaults/src/entrypoints/lifecycle/lifecycleServiceFactory.ts new file mode 100644 index 0000000000..3eb43d6c6e --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/lifecycle/lifecycleServiceFactory.ts @@ -0,0 +1,106 @@ +/* + * 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 { + LifecycleService, + LifecycleServiceShutdownHook, + LifecycleServiceShutdownOptions, + LifecycleServiceStartupHook, + LifecycleServiceStartupOptions, + LoggerService, + PluginMetadataService, + RootLifecycleService, + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; + +/** @internal */ +export class BackendPluginLifecycleImpl implements LifecycleService { + constructor( + private readonly logger: LoggerService, + private readonly rootLifecycle: RootLifecycleService, + private readonly pluginMetadata: PluginMetadataService, + ) {} + + #hasStarted = false; + #startupTasks: Array<{ + hook: LifecycleServiceStartupHook; + options?: LifecycleServiceStartupOptions; + }> = []; + + addStartupHook( + hook: LifecycleServiceStartupHook, + options?: LifecycleServiceStartupOptions, + ): void { + if (this.#hasStarted) { + throw new Error('Attempted to add startup hook after startup'); + } + this.#startupTasks.push({ hook, options }); + } + + async startup(): Promise { + if (this.#hasStarted) { + return; + } + this.#hasStarted = true; + + this.logger.debug( + `Running ${this.#startupTasks.length} plugin startup tasks...`, + ); + await Promise.all( + this.#startupTasks.map(async ({ hook, options }) => { + const logger = options?.logger ?? this.logger; + try { + await hook(); + logger.debug(`Plugin startup hook succeeded`); + } catch (error) { + logger.error(`Plugin startup hook failed, ${error}`); + } + }), + ); + } + + addShutdownHook( + hook: LifecycleServiceShutdownHook, + options?: LifecycleServiceShutdownOptions, + ): void { + const plugin = this.pluginMetadata.getId(); + this.rootLifecycle.addShutdownHook(hook, { + logger: options?.logger?.child({ plugin }) ?? this.logger, + }); + } +} + +/** + * Allows plugins to register shutdown hooks that are run when the process is about to exit. + * + * @public + */ +export const lifecycleServiceFactory = createServiceFactory({ + service: coreServices.lifecycle, + deps: { + logger: coreServices.logger, + rootLifecycle: coreServices.rootLifecycle, + pluginMetadata: coreServices.pluginMetadata, + }, + async factory({ rootLifecycle, logger, pluginMetadata }) { + return new BackendPluginLifecycleImpl( + logger, + rootLifecycle, + pluginMetadata, + ); + }, +}); diff --git a/packages/backend-defaults/src/entrypoints/permissions/index.ts b/packages/backend-defaults/src/entrypoints/permissions/index.ts new file mode 100644 index 0000000000..781dda31a0 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/permissions/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 { permissionsServiceFactory } from './permissionsServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/permissions/permissionsServiceFactory.ts b/packages/backend-defaults/src/entrypoints/permissions/permissionsServiceFactory.ts new file mode 100644 index 0000000000..f675dd6719 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/permissions/permissionsServiceFactory.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { ServerPermissionClient } from '@backstage/plugin-permission-node'; + +/** + * @public + */ +export const permissionsServiceFactory = createServiceFactory({ + service: coreServices.permissions, + deps: { + auth: coreServices.auth, + config: coreServices.rootConfig, + discovery: coreServices.discovery, + tokenManager: coreServices.tokenManager, + }, + async factory({ auth, config, discovery, tokenManager }) { + return ServerPermissionClient.fromConfig(config, { + auth, + discovery, + tokenManager, + }); + }, +}); diff --git a/packages/backend-defaults/src/entrypoints/rootConfig/index.ts b/packages/backend-defaults/src/entrypoints/rootConfig/index.ts new file mode 100644 index 0000000000..1775ef2efc --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootConfig/index.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 { rootConfigServiceFactory } from './rootConfigServiceFactory'; +export type { RootConfigFactoryOptions } from './rootConfigServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts new file mode 100644 index 0000000000..92d1a89c0f --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { + ConfigSources, + RemoteConfigSourceOptions, +} from '@backstage/config-loader'; + +/** + * @public + */ +export interface RootConfigFactoryOptions { + /** + * Process arguments to use instead of the default `process.argv()`. + */ + argv?: string[]; + + /** + * Enables and sets options for remote configuration loading. + */ + remote?: Pick; + watch?: boolean; +} + +/** + * @public + */ +export const rootConfigServiceFactory = createServiceFactory( + (options?: RootConfigFactoryOptions) => ({ + service: coreServices.rootConfig, + deps: {}, + async factory() { + const source = ConfigSources.default({ + argv: options?.argv, + remote: options?.remote, + watch: options?.watch, + }); + console.log(`Loading config from ${source}`); + return await ConfigSources.toConfig(source); + }, + }), +); diff --git a/packages/backend-defaults/src/entrypoints/rootLifecycle/index.ts b/packages/backend-defaults/src/entrypoints/rootLifecycle/index.ts new file mode 100644 index 0000000000..86589cd23e --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootLifecycle/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 { rootLifecycleServiceFactory } from './rootLifecycleServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.test.ts new file mode 100644 index 0000000000..91cb9031ae --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.test.ts @@ -0,0 +1,60 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { BackendLifecycleImpl } from './rootLifecycleServiceFactory'; + +describe('lifecycleService', () => { + it('should execute registered shutdown hook', async () => { + const service = new BackendLifecycleImpl(getVoidLogger()); + const hook = jest.fn(); + service.addShutdownHook(() => hook()); + // should not execute the hook more than once. + await service.shutdown(); + await service.shutdown(); + await service.shutdown(); + expect(hook).toHaveBeenCalledTimes(1); + }); + + it('should not throw errors', async () => { + const service = new BackendLifecycleImpl(getVoidLogger()); + service.addShutdownHook(() => { + throw new Error('oh no'); + }); + await expect(service.shutdown()).resolves.toBeUndefined(); + }); + + it('should not throw async errors', async () => { + const service = new BackendLifecycleImpl(getVoidLogger()); + service.addShutdownHook(async () => { + throw new Error('oh no'); + }); + await expect(service.shutdown()).resolves.toBeUndefined(); + }); + + it('should reject hooks after trigger', async () => { + const service = new BackendLifecycleImpl(getVoidLogger()); + await service.startup(); + expect(() => { + service.addStartupHook(() => {}); + }).toThrow('Attempted to add startup hook after startup'); + + await service.shutdown(); + expect(() => { + service.addShutdownHook(() => {}); + }).toThrow('Attempted to add shutdown hook after shutdown'); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.ts new file mode 100644 index 0000000000..197f99b97a --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.ts @@ -0,0 +1,120 @@ +/* + * 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 { + createServiceFactory, + coreServices, + LifecycleServiceStartupHook, + LifecycleServiceStartupOptions, + LifecycleServiceShutdownHook, + LifecycleServiceShutdownOptions, + RootLifecycleService, + LoggerService, +} from '@backstage/backend-plugin-api'; + +/** @internal */ +export class BackendLifecycleImpl implements RootLifecycleService { + constructor(private readonly logger: LoggerService) {} + + #hasStarted = false; + #startupTasks: Array<{ + hook: LifecycleServiceStartupHook; + options?: LifecycleServiceStartupOptions; + }> = []; + + addStartupHook( + hook: LifecycleServiceStartupHook, + options?: LifecycleServiceStartupOptions, + ): void { + if (this.#hasStarted) { + throw new Error('Attempted to add startup hook after startup'); + } + this.#startupTasks.push({ hook, options }); + } + + async startup(): Promise { + if (this.#hasStarted) { + return; + } + this.#hasStarted = true; + + this.logger.debug(`Running ${this.#startupTasks.length} startup tasks...`); + await Promise.all( + this.#startupTasks.map(async ({ hook, options }) => { + const logger = options?.logger ?? this.logger; + try { + await hook(); + logger.debug(`Startup hook succeeded`); + } catch (error) { + logger.error(`Startup hook failed, ${error}`); + } + }), + ); + } + + #hasShutdown = false; + #shutdownTasks: Array<{ + hook: LifecycleServiceShutdownHook; + options?: LifecycleServiceShutdownOptions; + }> = []; + + addShutdownHook( + hook: LifecycleServiceShutdownHook, + options?: LifecycleServiceShutdownOptions, + ): void { + if (this.#hasShutdown) { + throw new Error('Attempted to add shutdown hook after shutdown'); + } + this.#shutdownTasks.push({ hook, options }); + } + + async shutdown(): Promise { + if (this.#hasShutdown) { + return; + } + this.#hasShutdown = true; + + this.logger.debug( + `Running ${this.#shutdownTasks.length} shutdown tasks...`, + ); + await Promise.all( + this.#shutdownTasks.map(async ({ hook, options }) => { + const logger = options?.logger ?? this.logger; + try { + await hook(); + logger.debug(`Shutdown hook succeeded`); + } catch (error) { + logger.error(`Shutdown hook failed, ${error}`); + } + }), + ); + } +} + +/** + * Allows plugins to register shutdown hooks that are run when the process is about to exit. + * + * @public + */ +export const rootLifecycleServiceFactory = createServiceFactory({ + service: coreServices.rootLifecycle, + deps: { + logger: coreServices.rootLogger, + }, + async factory({ logger }) { + return new BackendLifecycleImpl(logger); + }, +}); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/database/migrateBackendTasks.ts b/packages/backend-defaults/src/entrypoints/scheduler/database/migrateBackendTasks.ts new file mode 100644 index 0000000000..959e6097f4 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/database/migrateBackendTasks.ts @@ -0,0 +1,31 @@ +/* + * 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 { resolvePackagePath } from '@backstage/backend-common'; +import { Knex } from 'knex'; +import { DB_MIGRATIONS_TABLE } from './tables'; + +export async function migrateBackendTasks(knex: Knex): Promise { + const migrationsDir = resolvePackagePath( + '@backstage/backend-defaults', + 'migrations/scheduler', + ); + + await knex.migrate.latest({ + directory: migrationsDir, + tableName: DB_MIGRATIONS_TABLE, + }); +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/database/tables.ts b/packages/backend-defaults/src/entrypoints/scheduler/database/tables.ts new file mode 100644 index 0000000000..63aad6e42a --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/database/tables.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const DB_MIGRATIONS_TABLE = 'backstage_backend_tasks__knex_migrations'; +export const DB_TASKS_TABLE = 'backstage_backend_tasks__tasks'; + +export type DbTasksRow = { + id: string; + settings_json: string; + next_run_start_at: Date; + current_run_ticket?: string; + current_run_started_at?: Date | string; + current_run_expires_at?: Date | string; +}; diff --git a/packages/backend-defaults/src/entrypoints/scheduler/index.ts b/packages/backend-defaults/src/entrypoints/scheduler/index.ts new file mode 100644 index 0000000000..77d4ea561d --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { schedulerServiceFactory } from './schedulerServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/LocalTaskWorker.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/LocalTaskWorker.test.ts new file mode 100644 index 0000000000..4fd4949478 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/LocalTaskWorker.test.ts @@ -0,0 +1,109 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { LocalTaskWorker } from './LocalTaskWorker'; + +describe('LocalTaskWorker', () => { + const logger = getVoidLogger(); + + it('runs the happy path (with iso duration) and handles cancellation', async () => { + const fn = jest.fn(); + const controller = new AbortController(); + + const worker = new LocalTaskWorker('a', fn, logger); + worker.start( + { + version: 2, + initialDelayDuration: 'PT0.2S', + cadence: 'PT0.2S', + timeoutAfterDuration: 'PT1S', + }, + { signal: controller.signal }, + ); + + // TODO(freben): Rewrite to fake timers - tried, but it wouldn't work + expect(fn).toHaveBeenCalledTimes(0); + await new Promise(r => setTimeout(r, 100)); + expect(fn).toHaveBeenCalledTimes(0); + await new Promise(r => setTimeout(r, 200)); + expect(fn).toHaveBeenCalledTimes(1); + await new Promise(r => setTimeout(r, 200)); + expect(fn).toHaveBeenCalledTimes(2); + controller.abort(); + await new Promise(r => setTimeout(r, 200)); + expect(fn).toHaveBeenCalledTimes(2); + }); + + it('runs the happy path (with a cron expression) and handles cancellation', async () => { + const fn = jest.fn(); + const controller = new AbortController(); + + // Await until system time is just past a second boundary (since cron is + // wall clock based) + await new Promise(r => setTimeout(r, 1000 - (Date.now() % 1000) + 10)); + + const worker = new LocalTaskWorker('a', fn, logger); + worker.start( + { + version: 2, + initialDelayDuration: 'PT0.2S', + cadence: '* * * * * *', + timeoutAfterDuration: 'PT1S', + }, + { signal: controller.signal }, + ); + + // TODO(freben): Rewrite to fake timers - tried, but it wouldn't work + expect(fn).toHaveBeenCalledTimes(0); + await new Promise(r => setTimeout(r, 100)); + expect(fn).toHaveBeenCalledTimes(0); + await new Promise(r => setTimeout(r, 200)); + expect(fn).toHaveBeenCalledTimes(1); + await new Promise(r => setTimeout(r, 1000)); + expect(fn).toHaveBeenCalledTimes(2); + controller.abort(); + await new Promise(r => setTimeout(r, 1000)); + expect(fn).toHaveBeenCalledTimes(2); + }); + + it('can trigger to abort wait', async () => { + const fn = jest.fn(); + const controller = new AbortController(); + + const worker = new LocalTaskWorker('a', fn, logger); + worker.start( + { + version: 2, + initialDelayDuration: 'PT0.2S', + cadence: 'PT0.2S', + timeoutAfterDuration: 'PT1S', + }, + { signal: controller.signal }, + ); + + // TODO(freben): Rewrite to fake timers - tried, but it wouldn't work + expect(fn).toHaveBeenCalledTimes(0); + await new Promise(r => setTimeout(r, 100)); + expect(fn).toHaveBeenCalledTimes(0); + await new Promise(r => setTimeout(r, 200)); + expect(fn).toHaveBeenCalledTimes(1); + worker.trigger(); + await new Promise(r => setTimeout(r, 10)); + expect(fn).toHaveBeenCalledTimes(2); + controller.abort(); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/LocalTaskWorker.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/LocalTaskWorker.ts new file mode 100644 index 0000000000..3510a855e9 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/LocalTaskWorker.ts @@ -0,0 +1,155 @@ +/* + * 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 { LoggerService } from '@backstage/backend-plugin-api'; +import { SchedulerServiceTaskFunction } from '@backstage/backend-plugin-api'; +import { ConflictError } from '@backstage/errors'; +import { CronTime } from 'cron'; +import { DateTime, Duration } from 'luxon'; +import { TaskSettingsV2 } from './types'; +import { delegateAbortController, sleep } from './util'; + +/** + * Implements tasks that run locally without cross-host collaboration. + * + * @private + */ +export class LocalTaskWorker { + private abortWait: AbortController | undefined; + + constructor( + private readonly taskId: string, + private readonly fn: SchedulerServiceTaskFunction, + private readonly logger: LoggerService, + ) {} + + start(settings: TaskSettingsV2, options?: { signal?: AbortSignal }) { + this.logger.info( + `Task worker starting: ${this.taskId}, ${JSON.stringify(settings)}`, + ); + + (async () => { + let attemptNum = 1; + for (;;) { + try { + if (settings.initialDelayDuration) { + await this.sleep( + Duration.fromISO(settings.initialDelayDuration), + options?.signal, + ); + } + + while (!options?.signal?.aborted) { + const startTime = process.hrtime(); + await this.runOnce(settings, options?.signal); + const timeTaken = process.hrtime(startTime); + await this.waitUntilNext( + settings, + (timeTaken[0] + timeTaken[1] / 1e9) * 1000, + options?.signal, + ); + } + + this.logger.info(`Task worker finished: ${this.taskId}`); + attemptNum = 0; + break; + } catch (e) { + attemptNum += 1; + this.logger.warn( + `Task worker failed unexpectedly, attempt number ${attemptNum}, ${e}`, + ); + await sleep(Duration.fromObject({ seconds: 1 })); + } + } + })(); + } + + trigger(): void { + if (!this.abortWait) { + throw new ConflictError(`Task ${this.taskId} is currently running`); + } + this.abortWait.abort(); + } + + /** + * Makes a single attempt at running the task to completion. + */ + private async runOnce( + settings: TaskSettingsV2, + signal?: AbortSignal, + ): Promise { + // Abort the task execution either if the worker is stopped, or if the + // task timeout is hit + const taskAbortController = delegateAbortController(signal); + const timeoutHandle = setTimeout(() => { + taskAbortController.abort(); + }, Duration.fromISO(settings.timeoutAfterDuration).as('milliseconds')); + + try { + await this.fn(taskAbortController.signal); + } catch (e) { + // ignore intentionally + } + + // release resources + clearTimeout(timeoutHandle); + taskAbortController.abort(); + } + + /** + * Sleeps until it's time to run the task again. + */ + private async waitUntilNext( + settings: TaskSettingsV2, + lastRunMillis: number, + signal?: AbortSignal, + ) { + if (signal?.aborted) { + return; + } + + const isCron = !settings.cadence.startsWith('P'); + let dt: number; + + if (isCron) { + const nextRun = +new CronTime(settings.cadence).sendAt().toJSDate(); + dt = nextRun - Date.now(); + } else { + dt = + Duration.fromISO(settings.cadence).as('milliseconds') - lastRunMillis; + } + + dt = Math.max(dt, 0); + + this.logger.debug( + `task: ${this.taskId} will next occur around ${DateTime.now().plus( + Duration.fromMillis(dt), + )}`, + ); + + await this.sleep(Duration.fromMillis(dt), signal); + } + + private async sleep( + duration: Duration, + abortSignal?: AbortSignal, + ): Promise { + this.abortWait = delegateAbortController(abortSignal); + await sleep(duration, this.abortWait.signal); + this.abortWait.abort(); // cleans up resources + this.abortWait = undefined; + } +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts new file mode 100644 index 0000000000..57faa6faf8 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts @@ -0,0 +1,349 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; +import { ConflictError, NotFoundError } from '@backstage/errors'; +import { Duration } from 'luxon'; +import { migrateBackendTasks } from '../database/migrateBackendTasks'; +import { + PluginTaskSchedulerImpl, + parseDuration, +} from './PluginTaskSchedulerImpl'; + +function defer() { + let resolve = () => {}; + const promise = new Promise(_resolve => { + resolve = _resolve; + }); + return { promise, resolve }; +} + +jest.setTimeout(60_000); + +describe('PluginTaskManagerImpl', () => { + const databases = TestDatabases.create({ + ids: ['POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], + }); + + beforeAll(async () => { + // Make sure all databases are running before mocking timers, in case of testcontainers + await Promise.all( + databases.eachSupportedId().map(([id]) => databases.init(id)), + ); + + jest.useFakeTimers(); + }, 60_000); + + async function init(databaseId: TestDatabaseId) { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + const manager = new PluginTaskSchedulerImpl( + async () => knex, + getVoidLogger(), + ); + return { knex, manager }; + } + + // This is just to test the wrapper code; most of the actual tests are in + // TaskWorker.test.ts + describe('scheduleTask with global scope', () => { + it.each(databases.eachSupportedId())( + 'can run the v1 happy path, %p', + async databaseId => { + const { manager } = await init(databaseId); + + const fn = jest.fn(); + const promise = new Promise(resolve => fn.mockImplementation(resolve)); + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromMillis(5000), + fn, + scope: 'global', + }); + + await promise; + expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal)); + }, + ); + + it.each(databases.eachSupportedId())( + 'can run the v2 happy path, %p', + async databaseId => { + const { manager } = await init(databaseId); + + const fn = jest.fn(); + const promise = new Promise(resolve => fn.mockImplementation(resolve)); + await manager.scheduleTask({ + id: 'task2', + timeout: Duration.fromMillis(5000), + frequency: { cron: '* * * * * *' }, + fn, + scope: 'global', + }); + + await promise; + expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal)); + }, + ); + }); + + describe('triggerTask with global scope', () => { + it.each(databases.eachSupportedId())( + 'can manually trigger a task, %p', + async databaseId => { + const { manager } = await init(databaseId); + + const fn = jest.fn(); + const promise = new Promise(resolve => fn.mockImplementation(resolve)); + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromObject({ years: 1 }), + initialDelay: Duration.fromObject({ years: 1 }), + fn, + scope: 'global', + }); + + await manager.triggerTask('task1'); + jest.advanceTimersByTime(5000); + + await promise; + expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal)); + }, + ); + + it.each(databases.eachSupportedId())( + 'cant trigger a non-existent task, %p', + async databaseId => { + const { manager } = await init(databaseId); + + const fn = jest.fn(); + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromObject({ years: 1 }), + fn, + scope: 'global', + }); + + await expect(() => manager.triggerTask('task2')).rejects.toThrow( + NotFoundError, + ); + }, + ); + + it.each(databases.eachSupportedId())( + 'cant trigger a running task, %p', + async databaseId => { + const { manager } = await init(databaseId); + + const { promise, resolve } = defer(); + + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromObject({ years: 1 }), + fn: async () => { + resolve(); + await new Promise(r => setTimeout(r, 20000)); + }, + scope: 'global', + }); + + await promise; + await expect(() => manager.triggerTask('task1')).rejects.toThrow( + ConflictError, + ); + }, + ); + }); + + // This is just to test the wrapper code; most of the actual tests are in + // TaskWorker.test.ts + describe('scheduleTask with local scope', () => { + it('can run the v1 happy path', async () => { + const { manager } = await init('SQLITE_3'); + + const fn = jest.fn(); + const promise = new Promise(resolve => fn.mockImplementation(resolve)); + await manager.scheduleTask({ + id: 'task1', + timeout: { milliseconds: 5000 }, + frequency: { milliseconds: 5000 }, + fn, + scope: 'local', + }); + + await promise; + expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal)); + }, 60_000); + + it('can run the v2 happy path', async () => { + const { manager } = await init('SQLITE_3'); + + const fn = jest.fn(); + const promise = new Promise(resolve => fn.mockImplementation(resolve)); + await manager.scheduleTask({ + id: 'task2', + timeout: Duration.fromMillis(5000), + frequency: { cron: '* * * * * *' }, + fn, + scope: 'local', + }); + + await promise; + expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal)); + }, 60_000); + }); + + describe('triggerTask with local scope', () => { + it('can manually trigger a task', async () => { + const { manager } = await init('SQLITE_3'); + + const fn = jest.fn(); + const promise = new Promise(resolve => fn.mockImplementation(resolve)); + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromObject({ years: 1 }), + initialDelay: Duration.fromObject({ years: 1 }), + fn, + scope: 'local', + }); + + await manager.triggerTask('task1'); + jest.advanceTimersByTime(5000); + + await promise; + expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal)); + }, 60_000); + + it('cant trigger a non-existent task', async () => { + const { manager } = await init('SQLITE_3'); + + const fn = jest.fn(); + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromObject({ years: 1 }), + fn, + scope: 'local', + }); + + await expect(() => manager.triggerTask('task2')).rejects.toThrow( + NotFoundError, + ); + }, 60_000); + + it('cant trigger a running task', async () => { + const { manager } = await init('SQLITE_3'); + + const { promise, resolve } = defer(); + + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromObject({ years: 1 }), + fn: async () => { + resolve(); + await new Promise(r => setTimeout(r, 20000)); + }, + scope: 'local', + }); + + await promise; + await expect(() => manager.triggerTask('task1')).rejects.toThrow( + ConflictError, + ); + }, 60_000); + }); + + // This is just to test the wrapper code; most of the actual tests are in + // TaskWorker.test.ts + describe('createScheduledTaskRunner', () => { + it.each(databases.eachSupportedId())( + 'can run the happy path, %p', + async databaseId => { + const { manager } = await init(databaseId); + + const fn = jest.fn(); + const promise = new Promise(resolve => fn.mockImplementation(resolve)); + await manager + .createScheduledTaskRunner({ + timeout: Duration.fromMillis(5000), + frequency: Duration.fromMillis(5000), + scope: 'global', + }) + .run({ + id: 'task1', + fn, + }); + + await promise; + expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal)); + }, + ); + }); + + describe('can fetch task ids', () => { + it.each(databases.eachSupportedId())( + 'can fetch both global and local task ids, %p', + async databaseId => { + const { manager } = await init(databaseId); + const fn = jest.fn(); + + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromMillis(5000), + fn, + scope: 'global', + }); + + await manager.scheduleTask({ + id: 'task2', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromMillis(5000), + fn, + scope: 'local', + }); + + await expect(manager.getScheduledTasks()).resolves.toEqual([ + { + id: 'task1', + scope: 'global', + settings: expect.objectContaining({ cadence: 'PT5S' }), + }, + { + id: 'task2', + scope: 'local', + settings: expect.objectContaining({ cadence: 'PT5S' }), + }, + ]); + }, + ); + }); + + describe('parseDuration', () => { + it('should parse durations', () => { + expect(parseDuration({ milliseconds: 5000 })).toEqual('PT5S'); + expect(parseDuration(Duration.fromMillis(5000))).toEqual('PT5S'); + expect(parseDuration({ cron: '1 * * * *' })).toEqual('1 * * * *'); + }); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts new file mode 100644 index 0000000000..62b36e024c --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts @@ -0,0 +1,170 @@ +/* + * 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 { + LoggerService, + SchedulerService, + SchedulerServiceTaskDescriptor, + SchedulerServiceTaskFunction, + SchedulerServiceTaskInvocationDefinition, + SchedulerServiceTaskRunner, + SchedulerServiceTaskScheduleDefinition, +} from '@backstage/backend-plugin-api'; +import { Counter, Histogram, metrics } from '@opentelemetry/api'; +import { Knex } from 'knex'; +import { Duration } from 'luxon'; +import { LocalTaskWorker } from './LocalTaskWorker'; +import { TaskWorker } from './TaskWorker'; +import { TaskSettingsV2 } from './types'; +import { validateId } from './util'; + +/** + * Implements the actual task management. + */ +export class PluginTaskSchedulerImpl implements SchedulerService { + private readonly localTasksById = new Map(); + private readonly allScheduledTasks: SchedulerServiceTaskDescriptor[] = []; + + private readonly counter: Counter; + private readonly duration: Histogram; + + constructor( + private readonly databaseFactory: () => Promise, + private readonly logger: LoggerService, + ) { + const meter = metrics.getMeter('default'); + this.counter = meter.createCounter('backend_tasks.task.runs.count', { + description: 'Total number of times a task has been run', + }); + this.duration = meter.createHistogram('backend_tasks.task.runs.duration', { + description: 'Histogram of task run durations', + unit: 'seconds', + }); + } + + async triggerTask(id: string): Promise { + const localTask = this.localTasksById.get(id); + if (localTask) { + localTask.trigger(); + return; + } + + const knex = await this.databaseFactory(); + await TaskWorker.trigger(knex, id); + } + + async scheduleTask( + task: SchedulerServiceTaskScheduleDefinition & + SchedulerServiceTaskInvocationDefinition, + ): Promise { + validateId(task.id); + const scope = task.scope ?? 'global'; + + const settings: TaskSettingsV2 = { + version: 2, + cadence: parseDuration(task.frequency), + initialDelayDuration: + task.initialDelay && parseDuration(task.initialDelay), + timeoutAfterDuration: parseDuration(task.timeout), + }; + + if (scope === 'global') { + const knex = await this.databaseFactory(); + const worker = new TaskWorker( + task.id, + this.wrapInMetrics(task.fn, { labels: { taskId: task.id, scope } }), + knex, + this.logger.child({ task: task.id }), + ); + await worker.start(settings, { signal: task.signal }); + } else { + const worker = new LocalTaskWorker( + task.id, + this.wrapInMetrics(task.fn, { labels: { taskId: task.id, scope } }), + this.logger.child({ task: task.id }), + ); + worker.start(settings, { signal: task.signal }); + this.localTasksById.set(task.id, worker); + } + + this.allScheduledTasks.push({ + id: task.id, + scope: scope, + settings: settings, + }); + } + + createScheduledTaskRunner( + schedule: SchedulerServiceTaskScheduleDefinition, + ): SchedulerServiceTaskRunner { + return { + run: async task => { + await this.scheduleTask({ ...task, ...schedule }); + }, + }; + } + + async getScheduledTasks(): Promise { + return this.allScheduledTasks; + } + + private wrapInMetrics( + fn: SchedulerServiceTaskFunction, + opts: { labels: Record }, + ): SchedulerServiceTaskFunction { + return async abort => { + const labels = { + ...opts.labels, + }; + this.counter.add(1, { ...labels, result: 'started' }); + + const startTime = process.hrtime(); + + try { + await fn(abort); + labels.result = 'completed'; + } catch (ex) { + labels.result = 'failed'; + throw ex; + } finally { + const delta = process.hrtime(startTime); + const endTime = delta[0] + delta[1] / 1e9; + this.counter.add(1, labels); + this.duration.record(endTime, labels); + } + }; + } +} + +export function parseDuration( + frequency: SchedulerServiceTaskScheduleDefinition['frequency'], +): string { + if ('cron' in frequency) { + return frequency.cron; + } + + const parsed = Duration.isDuration(frequency) + ? frequency + : Duration.fromObject(frequency); + + if (!parsed.isValid) { + throw new Error( + `Invalid duration, ${parsed.invalidReason}: ${parsed.invalidExplanation}`, + ); + } + + return parsed.toISO()!; +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.test.ts new file mode 100644 index 0000000000..82133a9e54 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.test.ts @@ -0,0 +1,96 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { TestDatabases } from '@backstage/backend-test-utils'; +import { Knex } from 'knex'; +import { Duration } from 'luxon'; +import waitForExpect from 'wait-for-expect'; +import { migrateBackendTasks } from '../database/migrateBackendTasks'; +import { DB_TASKS_TABLE, DbTasksRow } from '../database/tables'; +import { PluginTaskSchedulerJanitor } from './PluginTaskSchedulerJanitor'; +import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; + +const insertTask = async (knex: Knex, task: DbTasksRow) => { + return knex(DB_TASKS_TABLE) + .insert(task) + .onConflict('id') + .merge(['settings_json']); +}; + +const getTask = async (knex: Knex): Promise => { + return (await knex(DB_TASKS_TABLE))[0]; +}; + +describe('PluginTaskSchedulerJanitor', () => { + const logger = getVoidLogger(); + const databases = TestDatabases.create({ + ids: [ + /* 'MYSQL_8' not supported yet */ + 'POSTGRES_16', + 'POSTGRES_12', + 'SQLITE_3', + 'MYSQL_8', + ], + }); + const testScopedSignal = createTestScopedSignal(); + + jest.setTimeout(60_000); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it.each(databases.eachSupportedId())( + 'Should update date if current_run_expires_at expires, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const dateYesterday = new Date( + new Date().setDate(new Date().getDate() - 1), + ); + + await insertTask(knex, { + id: 'task1', + settings_json: '', + next_run_start_at: new Date('2023-03-01 00:00:00'), + current_run_ticket: 'ticket', + current_run_started_at: dateYesterday, + current_run_expires_at: dateYesterday, + }); + + const worker = new PluginTaskSchedulerJanitor({ + waitBetweenRuns: Duration.fromObject({ milliseconds: 20 }), + knex, + logger, + }); + + worker.start(testScopedSignal()); + + await waitForExpect(async () => { + await expect(getTask(knex)).resolves.toEqual( + expect.objectContaining({ + id: 'task1', + current_run_ticket: null, + current_run_started_at: null, + current_run_expires_at: null, + }), + ); + }); + }, + ); +}); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.ts new file mode 100644 index 0000000000..b0cd4572cf --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.ts @@ -0,0 +1,96 @@ +/* + * 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 { LoggerService } from '@backstage/backend-plugin-api'; +import { Knex } from 'knex'; +import { Duration } from 'luxon'; +import { DB_TASKS_TABLE, DbTasksRow } from '../database/tables'; +import { sleep } from './util'; + +/** + * Makes sure to auto-expire and clean up things that time out or for other + * reasons should not be left lingering. + */ +export class PluginTaskSchedulerJanitor { + private readonly knex: Knex; + private readonly waitBetweenRuns: Duration; + private readonly logger: LoggerService; + + constructor(options: { + knex: Knex; + waitBetweenRuns: Duration; + logger: LoggerService; + }) { + this.knex = options.knex; + this.waitBetweenRuns = options.waitBetweenRuns; + this.logger = options.logger; + } + + async start(abortSignal?: AbortSignal) { + while (!abortSignal?.aborted) { + try { + await this.runOnce(); + } catch (e) { + this.logger.warn(`Error while performing janitorial tasks, ${e}`); + } + + await sleep(this.waitBetweenRuns, abortSignal); + } + } + + private async runOnce() { + const dbNull = this.knex.raw('null'); + const configClient = this.knex.client.config.client; + + let tasks: Array<{ id: string }>; + if (configClient.includes('sqlite3') || configClient.includes('mysql')) { + tasks = await this.knex(DB_TASKS_TABLE) + .select('id') + .where('current_run_expires_at', '<', this.knex.fn.now()); + await this.knex(DB_TASKS_TABLE) + .whereIn( + 'id', + tasks.map(t => t.id), + ) + .update({ + current_run_ticket: dbNull, + current_run_started_at: dbNull, + current_run_expires_at: dbNull, + }); + } else { + tasks = await this.knex(DB_TASKS_TABLE) + .where('current_run_expires_at', '<', this.knex.fn.now()) + .update({ + current_run_ticket: dbNull, + current_run_started_at: dbNull, + current_run_expires_at: dbNull, + }) + .returning(['id']); + } + + // In rare cases, knex drivers may ignore "returning", and return the number + // of rows changed instead + if (typeof tasks === 'number') { + if (tasks > 0) { + this.logger.warn(`${tasks} tasks timed out and were lost`); + } + } else { + for (const { id } of tasks) { + this.logger.warn(`Task timed out and was lost: ${id}`); + } + } + } +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskScheduler.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskScheduler.test.ts new file mode 100644 index 0000000000..d286eaee38 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskScheduler.test.ts @@ -0,0 +1,84 @@ +/* + * 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 { DatabaseManager, getVoidLogger } from '@backstage/backend-common'; +import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; +import { Duration } from 'luxon'; +import waitForExpect from 'wait-for-expect'; +import { TaskScheduler } from './TaskScheduler'; +import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; + +jest.setTimeout(60_000); + +describe('TaskScheduler', () => { + const logger = getVoidLogger(); + const databases = TestDatabases.create(); + const testScopedSignal = createTestScopedSignal(); + + async function createDatabase( + databaseId: TestDatabaseId, + ): Promise { + const knex = await databases.init(databaseId); + const databaseManager: Partial = { + forPlugin: () => ({ + getClient: async () => knex, + }), + }; + return databaseManager as DatabaseManager; + } + + it.each(databases.eachSupportedId())( + 'can return a working v1 plugin impl, %p', + async databaseId => { + const database = await createDatabase(databaseId); + const manager = new TaskScheduler(database, logger).forPlugin('test'); + const fn = jest.fn(); + + await manager.scheduleTask({ + id: 'task1', + timeout: Duration.fromMillis(5000), + frequency: Duration.fromMillis(5000), + signal: testScopedSignal(), + fn, + }); + + await waitForExpect(() => { + expect(fn).toHaveBeenCalled(); + }); + }, + ); + + it.each(databases.eachSupportedId())( + 'can return a working v2 plugin impl, %p', + async databaseId => { + const database = await createDatabase(databaseId); + const manager = new TaskScheduler(database, logger).forPlugin('test'); + const fn = jest.fn(); + + await manager.scheduleTask({ + id: 'task2', + timeout: Duration.fromMillis(5000), + frequency: { cron: '* * * * * *' }, + signal: testScopedSignal(), + fn, + }); + + await waitForExpect(() => { + expect(fn).toHaveBeenCalled(); + }); + }, + ); +}); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskScheduler.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskScheduler.ts new file mode 100644 index 0000000000..21a19ce700 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskScheduler.ts @@ -0,0 +1,98 @@ +/* + * 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 { + DatabaseManager, + getRootLogger, + LegacyRootDatabaseService, + PluginDatabaseManager, +} from '@backstage/backend-common'; +import { + LoggerService, + RootConfigService, + SchedulerService, +} from '@backstage/backend-plugin-api'; +import { once } from 'lodash'; +import { Duration } from 'luxon'; +import { migrateBackendTasks } from '../database/migrateBackendTasks'; +import { PluginTaskSchedulerImpl } from './PluginTaskSchedulerImpl'; +import { PluginTaskSchedulerJanitor } from './PluginTaskSchedulerJanitor'; + +/** + * Deals with the scheduling of distributed tasks. + */ +export class TaskScheduler { + static fromConfig( + config: RootConfigService, + options?: { + databaseManager?: LegacyRootDatabaseService; + logger?: LoggerService; + }, + ): TaskScheduler { + const databaseManager = + options?.databaseManager ?? DatabaseManager.fromConfig(config); + const logger = (options?.logger || getRootLogger()).child({ + type: 'taskManager', + }); + return new TaskScheduler(databaseManager, logger); + } + + constructor( + private readonly databaseManager: LegacyRootDatabaseService, + private readonly logger: LoggerService, + ) {} + + /** + * Instantiates a task manager instance for the given plugin. + * + * @param pluginId - The unique ID of the plugin, for example "catalog" + * @returns A {@link SchedulerService} instance + */ + forPlugin(pluginId: string): SchedulerService { + return TaskScheduler.forPlugin({ + pluginId, + databaseManager: this.databaseManager.forPlugin(pluginId), + logger: this.logger, + }); + } + + static forPlugin(opts: { + pluginId: string; + databaseManager: PluginDatabaseManager; + logger: LoggerService; + }): SchedulerService { + const databaseFactory = once(async () => { + const knex = await opts.databaseManager.getClient(); + + if (!opts.databaseManager.migrations?.skip) { + await migrateBackendTasks(knex); + } + + if (process.env.NODE_ENV !== 'test') { + const janitor = new PluginTaskSchedulerJanitor({ + knex, + waitBetweenRuns: Duration.fromObject({ minutes: 1 }), + logger: opts.logger, + }); + janitor.start(); + } + + return knex; + }); + + return new PluginTaskSchedulerImpl(databaseFactory, opts.logger); + } +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.test.ts new file mode 100644 index 0000000000..20d9b63859 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.test.ts @@ -0,0 +1,507 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { TestDatabases } from '@backstage/backend-test-utils'; +import { DateTime, Duration } from 'luxon'; +import waitForExpect from 'wait-for-expect'; +import { migrateBackendTasks } from '../database/migrateBackendTasks'; +import { DB_TASKS_TABLE, DbTasksRow } from '../database/tables'; +import { TaskWorker } from './TaskWorker'; +import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; +import { TaskSettingsV2 } from './types'; + +jest.setTimeout(60_000); + +describe('TaskWorker', () => { + const logger = getVoidLogger(); + const databases = TestDatabases.create(); + const testScopedSignal = createTestScopedSignal(); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it.each(databases.eachSupportedId())( + 'goes through the expected states, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn( + async () => new Promise(resolve => setTimeout(resolve, 50)), + ); + const settings: TaskSettingsV2 = { + version: 2, + cadence: '*/2 * * * * *', + initialDelayDuration: Duration.fromObject({ seconds: 1 }).toISO()!, + timeoutAfterDuration: Duration.fromObject({ minutes: 1 }).toISO()!, + }; + + const worker = new TaskWorker('task1', fn, knex, logger); + await worker.persistTask(settings); + + let row = (await knex(DB_TASKS_TABLE))[0]; + expect(row).toEqual( + expect.objectContaining({ + id: 'task1', + current_run_ticket: null, + current_run_started_at: null, + current_run_expires_at: null, + }), + ); + expect(JSON.parse(row.settings_json)).toEqual({ + version: 2, + cadence: '*/2 * * * * *', + initialDelayDuration: 'PT1S', + timeoutAfterDuration: 'PT1M', + }); + + await expect(worker.findReadyTask()).resolves.toEqual({ + result: 'not-ready-yet', + }); + + await waitForExpect(async () => { + await expect(worker.findReadyTask()).resolves.toEqual({ + result: 'ready', + settings, + }); + }); + + row = (await knex(DB_TASKS_TABLE))[0]; + expect(row).toEqual( + expect.objectContaining({ + id: 'task1', + current_run_ticket: null, + current_run_started_at: null, + current_run_expires_at: null, + }), + ); + + await expect(worker.tryClaimTask('ticket', settings)).resolves.toBe(true); + + row = (await knex(DB_TASKS_TABLE))[0]; + expect(row).toEqual( + expect.objectContaining({ + id: 'task1', + current_run_ticket: 'ticket', + current_run_started_at: expect.anything(), + current_run_expires_at: expect.anything(), + }), + ); + + await expect(worker.tryReleaseTask('ticket', settings)).resolves.toBe( + true, + ); + + row = (await knex(DB_TASKS_TABLE))[0]; + expect(row).toEqual( + expect.objectContaining({ + id: 'task1', + current_run_ticket: null, + current_run_started_at: null, + current_run_expires_at: null, + }), + ); + }, + ); + + it.each(databases.eachSupportedId())( + 'logs error when the task throws, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + jest.spyOn(logger, 'error'); + const fn = jest.fn().mockRejectedValue(new Error('failed')); + const settings: TaskSettingsV2 = { + version: 2, + initialDelayDuration: undefined, + cadence: '* * * * * *', + timeoutAfterDuration: Duration.fromMillis(60000).toISO()!, + }; + const checkFrequency = Duration.fromObject({ milliseconds: 100 }); + const worker = new TaskWorker('task1', fn, knex, logger, checkFrequency); + worker.start(settings, { signal: testScopedSignal() }); + + await waitForExpect(() => { + expect(logger.error).toHaveBeenCalled(); + }); + }, + ); + + it.each(databases.eachSupportedId())( + 'runs tasks more than once even when the task throws, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn().mockRejectedValue(new Error('failed')); + const settings: TaskSettingsV2 = { + version: 2, + initialDelayDuration: undefined, + cadence: '* * * * * *', + timeoutAfterDuration: Duration.fromMillis(60000).toISO()!, + }; + const checkFrequency = Duration.fromObject({ milliseconds: 100 }); + const worker = new TaskWorker('task1', fn, knex, logger, checkFrequency); + worker.start(settings, { signal: testScopedSignal() }); + + await waitForExpect(() => { + expect(fn).toHaveBeenCalledTimes(3); + }); + }, + ); + + it.each(databases.eachSupportedId())( + 'does not clobber ticket lock when stolen, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn( + async () => new Promise(resolve => setTimeout(resolve, 50)), + ); + const settings: TaskSettingsV2 = { + version: 2, + initialDelayDuration: undefined, + cadence: '* * * * * *', + timeoutAfterDuration: Duration.fromMillis(60000).toISO()!, + }; + + const worker = new TaskWorker('task1', fn, knex, logger); + await worker.persistTask(settings); + + await waitForExpect(async () => { + await expect(worker.findReadyTask()).resolves.toEqual({ + result: 'ready', + settings, + }); + }); + + await expect(worker.tryClaimTask('ticket', settings)).resolves.toBe(true); + + let row = (await knex(DB_TASKS_TABLE))[0]; + expect(row).toEqual( + expect.objectContaining({ + id: 'task1', + current_run_ticket: 'ticket', + current_run_started_at: expect.anything(), + current_run_expires_at: expect.anything(), + }), + ); + + await knex(DB_TASKS_TABLE) + .where('id', '=', 'task1') + .update({ current_run_ticket: 'stolen' }); + + await expect(worker.tryReleaseTask('ticket', settings)).resolves.toBe( + false, + ); + + row = (await knex(DB_TASKS_TABLE))[0]; + expect(row).toEqual( + expect.objectContaining({ + id: 'task1', + current_run_ticket: 'stolen', + current_run_started_at: expect.anything(), + current_run_expires_at: expect.anything(), + }), + ); + }, + ); + + it.each(databases.eachSupportedId())( + 'gracefully handles a disappeared task row, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn(async () => {}); + const settings: TaskSettingsV2 = { + version: 2, + initialDelayDuration: undefined, + cadence: '* * * * * *', + timeoutAfterDuration: Duration.fromMillis(60000).toISO()!, + }; + + const worker1 = new TaskWorker('task1', fn, knex, logger); + await worker1.persistTask(settings); + await knex(DB_TASKS_TABLE).where('id', '=', 'task1').delete(); + await expect(worker1.findReadyTask()).resolves.toEqual({ + result: 'abort', + }); + + const worker2 = new TaskWorker('task2', fn, knex, logger); + await worker2.persistTask(settings); + + await waitForExpect(async () => { + await expect(worker2.findReadyTask()).resolves.toEqual({ + result: 'ready', + settings, + }); + }); + + await knex(DB_TASKS_TABLE).where('id', '=', 'task2').delete(); + await expect(worker2.tryClaimTask('ticket', settings)).resolves.toBe( + false, + ); + + const worker3 = new TaskWorker('task3', fn, knex, logger); + await worker3.persistTask(settings); + + await waitForExpect(async () => { + await expect(worker3.findReadyTask()).resolves.toEqual({ + result: 'ready', + settings, + }); + }); + + await expect(worker3.tryClaimTask('ticket', settings)).resolves.toBe( + true, + ); + await knex(DB_TASKS_TABLE).where('id', '=', 'task3').delete(); + await expect(worker3.tryReleaseTask('ticket', settings)).resolves.toBe( + false, + ); + }, + ); + + it.each(databases.eachSupportedId())( + 'respects initialDelayDuration per worker, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const abortFirst = new AbortController(); + const settings: TaskSettingsV2 = { + version: 2, + initialDelayDuration: 'PT0.3S', + cadence: 'PT0.1S', + timeoutAfterDuration: 'PT10S', + }; + + // Start a single worker and make sure it waits and then goes to work + const fn1 = jest.fn(async () => {}); + const worker1 = new TaskWorker( + 'task1', + fn1, + knex, + logger, + Duration.fromMillis(10), + ); + await worker1.start(settings, { signal: abortFirst.signal }); + + expect(fn1).toHaveBeenCalledTimes(0); + await new Promise(resolve => setTimeout(resolve, 250)); + expect(fn1).toHaveBeenCalledTimes(0); + await new Promise(resolve => setTimeout(resolve, 100)); + expect(fn1.mock.calls.length).toBeGreaterThan(0); + + // Start a second worker and make sure it waits but the first worker still works along + const fn2 = jest.fn(); + const promise2 = new Promise(resolve => fn2.mockImplementation(resolve)); + const worker2 = new TaskWorker( + 'task1', + fn2, + knex, + logger, + Duration.fromMillis(10), + ); + await worker2.start(settings, { signal: testScopedSignal() }); + + // We eventually abort the first worker just to make sure that the second + // one for sure will get a go at running the task + setTimeout(() => abortFirst.abort(), 1000); + + const before = fn1.mock.calls.length; + await promise2; + expect(fn1.mock.calls.length).toBeGreaterThan(before); + + await knex.destroy(); + }, + ); + + it.each(databases.eachSupportedId())( + 'next_run_start_at is always the min between schedule changes from cron frequency, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn( + async () => new Promise(resolve => setTimeout(resolve, 50)), + ); + const settings: TaskSettingsV2 = { + version: 2, + cadence: '*/15 * * * *', + initialDelayDuration: 'PT2M', + timeoutAfterDuration: 'PT1M', + }; + + const worker = new TaskWorker('task99', fn, knex, logger); + await worker.persistTask(settings); + const row1 = (await knex(DB_TASKS_TABLE))[0]; + + const settings2 = { + ...settings, + cadence: '*/2 * * * *', + initialDelayDuration: 'PT1M', + }; + await worker.persistTask(settings2); + const row2 = (await knex(DB_TASKS_TABLE))[0]; + + expect(row2.next_run_start_at).not.toStrictEqual(row1.next_run_start_at); + + const settings3 = { ...settings }; + await worker.persistTask(settings3); + const row3 = (await knex(DB_TASKS_TABLE))[0]; + + // The new timestamp can basically be 0 or a minute depending on how the + // initialDelayDuration falls right on a cron boundary. This kinda + // contrived check removes a test flakiness based on wall clock time. + expect( + Math.abs( + +new Date(row3.next_run_start_at) - +new Date(row2.next_run_start_at), + ), + ).toBeLessThanOrEqual(60_000); + + await knex.destroy(); + }, + ); + + it.each(databases.eachSupportedId())( + 'next_run_start_at is always the min between schedule changes when using human duration frequency, %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: 'PT120M', + timeoutAfterDuration: 'PT1M', + }; + + const worker = new TaskWorker('task99', fn, knex, logger); + await worker.persistTask(initialSettings); + // replicate task running, sets next_run_start_at based on cadence + await worker.tryClaimTask('ticket', initialSettings); + await worker.tryReleaseTask('ticket', initialSettings); + + // grab initial row for comparisons later + const rowAfterClaimAndRelease = ( + await knex(DB_TASKS_TABLE) + )[0]; + + const settings: TaskSettingsV2 = { + ...initialSettings, + cadence: 'PT60M', + }; + await worker.persistTask(settings); + const row1 = (await knex(DB_TASKS_TABLE))[0]; + + const rowAfterClaimAndReleaseNextStartAt = DateTime.fromJSDate( + new Date(rowAfterClaimAndRelease.next_run_start_at), + ); + const row1NextStartAt = DateTime.fromJSDate( + new Date(row1.next_run_start_at), + ); + const now = DateTime.now(); + expect( + rowAfterClaimAndReleaseNextStartAt.diff(row1NextStartAt).as('minutes'), + ).toBeCloseTo(60, 1); // ensure that next start at is sooner than initial by one hour + expect(row1NextStartAt.diff(now).as('minutes')).toBeCloseTo(60, 1); // ensure that next start at is later than now by one hour + expect( + rowAfterClaimAndReleaseNextStartAt.diff(now).as('minutes'), + ).toBeCloseTo(120, 1); + + const settings2 = { + ...settings, + }; + await worker.persistTask(settings2); + const row2 = (await knex(DB_TASKS_TABLE))[0]; + + expect(row2.next_run_start_at).toStrictEqual(row1.next_run_start_at); + + await knex.destroy(); + }, + ); + + it.each(databases.eachSupportedId())( + 'next_run_start_at is always the min between schedule changes when using human duration frequency with initial start delay, %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: 'PT120M', + initialDelayDuration: 'PT2M', + timeoutAfterDuration: 'PT1M', + }; + + const worker = new TaskWorker('task99', fn, knex, logger); + await worker.persistTask(initialSettings); + // replicate task running, sets next_run_start_at based on cadence + await worker.tryClaimTask('ticket', initialSettings); + await worker.tryReleaseTask('ticket', initialSettings); + + // grab initial row for comparisons later + const rowAfterClaimAndRelease = ( + await knex(DB_TASKS_TABLE) + )[0]; + + const settings: TaskSettingsV2 = { + ...initialSettings, + cadence: 'PT60M', + }; + await worker.persistTask(settings); + const row1 = (await knex(DB_TASKS_TABLE))[0]; + + const rowAfterClaimAndReleaseNextStartAt = DateTime.fromJSDate( + new Date(rowAfterClaimAndRelease.next_run_start_at), + ); + const row1NextStartAt = DateTime.fromJSDate( + new Date(row1.next_run_start_at), + ); + const now = DateTime.now(); + expect( + rowAfterClaimAndReleaseNextStartAt.diff(row1NextStartAt).as('minutes'), + ).toBeCloseTo(62, 1); // ensure that next start at is sooner than initial by one hour, plus the 2 minute delay (set my tryReleaseTask) + expect(row1NextStartAt.diff(now).as('minutes')).toBeCloseTo(60, 1); // ensure that next start at is later than now by one hour (2 minute delay doesn't take effect here) + expect( + rowAfterClaimAndReleaseNextStartAt.diff(now).as('minutes'), + ).toBeCloseTo(122, 1); // includes 2 minute start delay (which is persisted from tryReleaseTask) + + const settings2 = { + ...settings, + }; + await worker.persistTask(settings2); + const row2 = (await knex(DB_TASKS_TABLE))[0]; + + expect(row2.next_run_start_at).toStrictEqual(row1.next_run_start_at); + + 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 new file mode 100644 index 0000000000..a1c4ec44fd --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/TaskWorker.ts @@ -0,0 +1,373 @@ +/* + * 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 { LoggerService } from '@backstage/backend-plugin-api'; +import { ConflictError, NotFoundError } from '@backstage/errors'; +import { CronTime } from 'cron'; +import { Knex } from 'knex'; +import { DateTime, Duration } from 'luxon'; +import { v4 as uuid } from 'uuid'; +import { DB_TASKS_TABLE, DbTasksRow } from '../database/tables'; +import { TaskSettingsV2, taskSettingsV2Schema } from './types'; +import { delegateAbortController, nowPlus, sleep } from './util'; +import { SchedulerServiceTaskFunction } from '@backstage/backend-plugin-api'; + +const DEFAULT_WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 }); + +/** + * Implements tasks that run across worker hosts, with collaborative locking. + * + * @private + */ +export class TaskWorker { + constructor( + private readonly taskId: string, + private readonly fn: SchedulerServiceTaskFunction, + private readonly knex: Knex, + private readonly logger: LoggerService, + private readonly workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY, + ) {} + + async start(settings: TaskSettingsV2, options?: { signal?: AbortSignal }) { + try { + await this.persistTask(settings); + } catch (e) { + throw new Error(`Failed to persist task, ${e}`); + } + + this.logger.info( + `Task worker starting: ${this.taskId}, ${JSON.stringify(settings)}`, + ); + + let workCheckFrequency = this.workCheckFrequency; + const isCron = !settings?.cadence.startsWith('P'); + if (!isCron) { + const cadence = Duration.fromISO(settings.cadence); + if (cadence < workCheckFrequency) { + workCheckFrequency = cadence; + } + } + + let attemptNum = 1; + (async () => { + for (;;) { + try { + if (settings.initialDelayDuration) { + await sleep( + Duration.fromISO(settings.initialDelayDuration), + options?.signal, + ); + } + + while (!options?.signal?.aborted) { + const runResult = await this.runOnce(options?.signal); + + if (runResult.result === 'abort') { + break; + } + + await sleep(workCheckFrequency, options?.signal); + } + + this.logger.info(`Task worker finished: ${this.taskId}`); + attemptNum = 0; + break; + } catch (e) { + attemptNum += 1; + this.logger.warn( + `Task worker failed unexpectedly, attempt number ${attemptNum}, ${e}`, + ); + await sleep(Duration.fromObject({ seconds: 1 })); + } + } + })(); + } + + static async trigger(knex: Knex, taskId: string): Promise { + // check if task exists + const rows = await knex(DB_TASKS_TABLE) + .select(knex.raw(1)) + .where('id', '=', taskId); + if (rows.length !== 1) { + throw new NotFoundError(`Task ${taskId} does not exist`); + } + + const updatedRows = await knex(DB_TASKS_TABLE) + .where('id', '=', taskId) + .whereNull('current_run_ticket') + .update({ + next_run_start_at: knex.fn.now(), + }); + if (updatedRows < 1) { + throw new ConflictError(`Task ${taskId} is currently running`); + } + } + + /** + * Makes a single attempt at running the task to completion, if ready. + * + * @returns The outcome of the attempt + */ + private async runOnce( + signal?: AbortSignal, + ): Promise< + | { result: 'not-ready-yet' } + | { result: 'abort' } + | { result: 'failed' } + | { result: 'completed' } + > { + const findResult = await this.findReadyTask(); + if ( + findResult.result === 'not-ready-yet' || + findResult.result === 'abort' + ) { + return findResult; + } + + const taskSettings = findResult.settings; + const ticket = uuid(); + + const claimed = await this.tryClaimTask(ticket, taskSettings); + if (!claimed) { + return { result: 'not-ready-yet' }; + } + + // Abort the task execution either if the worker is stopped, or if the + // task timeout is hit + const taskAbortController = delegateAbortController(signal); + const timeoutHandle = setTimeout(() => { + taskAbortController.abort(); + }, Duration.fromISO(taskSettings.timeoutAfterDuration).as('milliseconds')); + + try { + await this.fn(taskAbortController.signal); + taskAbortController.abort(); // releases resources + } catch (e) { + this.logger.error(e); + await this.tryReleaseTask(ticket, taskSettings); + return { result: 'failed' }; + } finally { + clearTimeout(timeoutHandle); + } + + await this.tryReleaseTask(ticket, taskSettings); + return { result: 'completed' }; + } + + /** + * Perform the initial store of the task info + */ + async persistTask(settings: TaskSettingsV2) { + // Perform an initial parse to ensure that we will definitely be able to + // read it back again. + taskSettingsV2Schema.parse(settings); + + const isCron = !settings?.cadence.startsWith('P'); + + let startAt: Knex.Raw | undefined; + let nextStartAt: Knex.Raw | undefined; + if (settings.initialDelayDuration) { + startAt = nowPlus( + Duration.fromISO(settings.initialDelayDuration), + this.knex, + ); + } + + if (isCron) { + const time = new CronTime(settings.cadence) + .sendAt() + .minus({ seconds: 1 }) // immediately, if "* * * * * *" + .toUTC(); + + nextStartAt = this.nextRunAtRaw(time); + startAt ||= nextStartAt; + } else { + startAt ||= this.knex.fn.now(); + nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex); + } + + this.logger.debug(`task: ${this.taskId} configured to run at: ${startAt}`); + + // It's OK if the task already exists; if it does, just replace its + // settings with the new value and start the loop as usual. + const settingsJson = JSON.stringify(settings); + await this.knex(DB_TASKS_TABLE) + .insert({ + id: this.taskId, + settings_json: settingsJson, + next_run_start_at: startAt, + }) + .onConflict('id') + .merge( + this.knex.client.config.client.includes('mysql') + ? { + settings_json: settingsJson, + next_run_start_at: this.knex.raw( + `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`, + [ + nextStartAt, + 'next_run_start_at', + nextStartAt, + 'next_run_start_at', + ], + ), + } + : { + settings_json: this.knex.ref('excluded.settings_json'), + next_run_start_at: this.knex.raw( + `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`, + [ + nextStartAt, + `${DB_TASKS_TABLE}.next_run_start_at`, + nextStartAt, + `${DB_TASKS_TABLE}.next_run_start_at`, + ], + ), + }, + ); + } + + /** + * Check if the task is ready to run + */ + async findReadyTask(): Promise< + | { result: 'not-ready-yet' } + | { result: 'abort' } + | { result: 'ready'; settings: TaskSettingsV2 } + > { + const [row] = await this.knex(DB_TASKS_TABLE) + .where('id', '=', this.taskId) + .select({ + settingsJson: 'settings_json', + ready: this.knex.raw( + `CASE + WHEN next_run_start_at <= ? AND current_run_ticket IS NULL THEN TRUE + ELSE FALSE + END`, + [this.knex.fn.now()], + ), + }); + + if (!row) { + this.logger.info( + 'No longer able to find task; aborting and assuming that it has been unregistered or expired', + ); + return { result: 'abort' }; + } else if (!row.ready) { + return { result: 'not-ready-yet' }; + } + + try { + const obj = JSON.parse(row.settingsJson); + const settings = taskSettingsV2Schema.parse(obj); + return { result: 'ready', settings }; + } catch (e) { + this.logger.info( + `Task "${this.taskId}" is no longer able to parse task settings; aborting and assuming that a ` + + `newer version of the task has been issued and being handled by other workers, ${e}`, + ); + return { result: 'abort' }; + } + } + + /** + * Attempts to claim a task that's ready for execution, on this worker's + * behalf. We should not attempt to perform the work unless the claim really + * goes through. + * + * @param ticket - A globally unique string that changes for each invocation + * @param settings - The settings of the task to claim + * @returns True if it was successfully claimed + */ + async tryClaimTask( + ticket: string, + settings: TaskSettingsV2, + ): Promise { + const startedAt = this.knex.fn.now(); + const expiresAt = settings.timeoutAfterDuration + ? nowPlus(Duration.fromISO(settings.timeoutAfterDuration), this.knex) + : this.knex.raw('null'); + + const rows = await this.knex(DB_TASKS_TABLE) + .where('id', '=', this.taskId) + .whereNull('current_run_ticket') + .update({ + current_run_ticket: ticket, + current_run_started_at: startedAt, + current_run_expires_at: expiresAt, + }); + + return rows === 1; + } + + async tryReleaseTask( + ticket: string, + settings: TaskSettingsV2, + ): Promise { + const isCron = !settings?.cadence.startsWith('P'); + + let nextRun: Knex.Raw; + if (isCron) { + const time = new CronTime(settings.cadence).sendAt().toUTC(); + this.logger.debug(`task: ${this.taskId} will next occur around ${time}`); + + nextRun = this.nextRunAtRaw(time); + } else { + const dt = Duration.fromISO(settings.cadence).as('seconds'); + this.logger.debug( + `task: ${this.taskId} will next occur around ${DateTime.now().plus({ + seconds: dt, + })}`, + ); + + if (this.knex.client.config.client.includes('sqlite3')) { + nextRun = this.knex.raw( + `max(datetime(next_run_start_at, ?), datetime('now'))`, + [`+${dt} seconds`], + ); + } else if (this.knex.client.config.client.includes('mysql')) { + nextRun = this.knex.raw( + `greatest(next_run_start_at + interval ${dt} second, now())`, + ); + } else { + nextRun = this.knex.raw( + `greatest(next_run_start_at + interval '${dt} seconds', now())`, + ); + } + } + + const rows = await this.knex(DB_TASKS_TABLE) + .where('id', '=', this.taskId) + .where('current_run_ticket', '=', ticket) + .update({ + next_run_start_at: nextRun, + current_run_ticket: this.knex.raw('null'), + current_run_started_at: this.knex.raw('null'), + current_run_expires_at: this.knex.raw('null'), + }); + + return rows === 1; + } + + private nextRunAtRaw(time: DateTime): Knex.Raw { + if (this.knex.client.config.client.includes('sqlite3')) { + return this.knex.raw('datetime(?)', [time.toISO()]); + } else if (this.knex.client.config.client.includes('mysql')) { + return this.knex.raw(`?`, [time.toSQL({ includeOffset: false })]); + } + return this.knex.raw(`?`, [time.toISO()]); + } +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/__testUtils__/createTestScopedSignal.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/__testUtils__/createTestScopedSignal.ts new file mode 100644 index 0000000000..6a497ea266 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/__testUtils__/createTestScopedSignal.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function createTestScopedSignal(): () => AbortSignal { + let testAbortController = new AbortController(); + + beforeEach(() => { + testAbortController = new AbortController(); + }); + afterEach(() => { + testAbortController.abort(); + }); + + return () => testAbortController.signal; +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts new file mode 100644 index 0000000000..61e6c1d9a8 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/types.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CronTime } from 'cron'; +import { Duration } from 'luxon'; +import { z } from 'zod'; + +function isValidOptionalDurationString(d: string | undefined): boolean { + try { + return !d || Duration.fromISO(d).isValid; + } catch { + return false; + } +} + +function isValidCronFormat(c: string | undefined): boolean { + try { + if (!c) { + return false; + } + // parse cron format to ensure it's a valid format. + // eslint-disable-next-line no-new + new CronTime(c); + return true; + } catch { + return false; + } +} + +export const taskSettingsV1Schema = z.object({ + version: z.literal(1), + initialDelayDuration: z + .string() + .optional() + .refine(isValidOptionalDurationString, { + message: 'Invalid duration, expecting ISO Period', + }), + recurringAtMostEveryDuration: z + .string() + .refine(isValidOptionalDurationString, { + message: 'Invalid duration, expecting ISO Period', + }), + timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, { + message: 'Invalid duration, expecting ISO Period', + }), +}); + +/** + * The properties that control a scheduled task (version 1). + */ +export type TaskSettingsV1 = z.infer; + +export const taskSettingsV2Schema = z.object({ + version: z.literal(2), + cadence: z + .string() + .refine(isValidCronFormat, { message: 'Invalid cron' }) + .or( + z.string().refine(isValidOptionalDurationString, { + message: 'Invalid duration, expecting ISO Period', + }), + ), + timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, { + message: 'Invalid duration, expecting ISO Period', + }), + initialDelayDuration: z + .string() + .optional() + .refine(isValidOptionalDurationString, { + message: 'Invalid duration, expecting ISO Period', + }), +}); + +/** + * The properties that control a scheduled task (version 2). + */ +export type TaskSettingsV2 = z.infer; diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/util.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/util.test.ts new file mode 100644 index 0000000000..e2536abb88 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/util.test.ts @@ -0,0 +1,113 @@ +/* + * 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 knexFactory, { Knex } from 'knex'; +import { Duration } from 'luxon'; +import { delegateAbortController, nowPlus, sleep, validateId } from './util'; + +class KnexBuilder { + public build(client: string): Knex { + return knexFactory({ client, useNullAsDefault: true }); + } +} + +describe('util', () => { + describe('validateId', () => { + it.each(['a', 'a_b', 'ab123c_2', 'a!', 'A', 'a-b', 'a.b', '_a', 'a_'])( + 'accepts valid inputs, %p', + async input => { + expect(validateId(input)).toBeUndefined(); + }, + ); + + it.each(['', null, Symbol('a')])( + 'rejects invalid inputs, %p', + async input => { + expect(() => validateId(input as any)).toThrow(); + }, + ); + }); + + describe('sleep', () => { + it('finishes the wait as expected with no signal', async () => { + const ac = new AbortController(); + const start = Date.now(); + await sleep(Duration.fromObject({ seconds: 1 }), ac.signal); + expect(Date.now() - start).toBeGreaterThan(800); + }, 5_000); + + it('aborts properly on the signal', async () => { + const ac = new AbortController(); + const promise = sleep(Duration.fromObject({ seconds: 10 }), ac.signal); + ac.abort(); + await promise; + expect(true).toBe(true); + }, 1_000); + }); + + describe('delegateAbortController', () => { + it('inherits parent abort state', () => { + const parent = new AbortController(); + const child = delegateAbortController(parent.signal); + expect(parent.signal.aborted).toBe(false); + expect(child.signal.aborted).toBe(false); + parent.abort(); + expect(parent.signal.aborted).toBe(true); + expect(child.signal.aborted).toBe(true); + }); + + it('does not inherit from child to parent', () => { + const parent = new AbortController(); + const child = delegateAbortController(parent.signal); + expect(parent.signal.aborted).toBe(false); + expect(child.signal.aborted).toBe(false); + child.abort(); + expect(parent.signal.aborted).toBe(false); + expect(child.signal.aborted).toBe(true); + }); + }); + + describe('nowPlus', () => { + describe('without duration', () => { + const databases = [ + { client: 'sqlite3', expected: 'CURRENT_TIMESTAMP' }, + { client: 'mysql2', expected: 'CURRENT_TIMESTAMP' }, + { client: 'pg', expected: 'CURRENT_TIMESTAMP' }, + ]; + + it.each(databases)('for client $client', ({ client, expected }) => { + const knex = new KnexBuilder().build(client); + const result = nowPlus(undefined, knex); + + expect(result.toString()).toBe(expected); + }); + }); + describe('With duration', () => { + const databases = [ + { client: 'sqlite3', expected: "datetime('now', '20 seconds')" }, + { client: 'mysql2', expected: 'now() + interval 20 second' }, + { client: 'pg', expected: "now() + interval '20 seconds'" }, + ]; + it.each(databases)('for client $client', ({ client, expected }) => { + const duration = Duration.fromObject({ seconds: 20 }); + const knex = new KnexBuilder().build(client); + const result = nowPlus(duration, knex); + + expect(result.toString()).toBe(expected); + }); + }); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/util.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/util.ts new file mode 100644 index 0000000000..70d67a9fbe --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/util.ts @@ -0,0 +1,111 @@ +/* + * 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 { InputError } from '@backstage/errors'; +import { Knex } from 'knex'; +import { DateTime, Duration } from 'luxon'; + +// Keep the IDs compatible with e.g. Prometheus labels +export function validateId(id: string) { + if (typeof id !== 'string' || !id.trim()) { + throw new InputError(`${id} is not a valid ID, expected non-empty string`); + } +} + +export function dbTime(t: Date | string): DateTime { + if (typeof t === 'string') { + return DateTime.fromSQL(t); + } + return DateTime.fromJSDate(t); +} + +export function nowPlus(duration: Duration | undefined, knex: Knex) { + const seconds = duration?.as('seconds') ?? 0; + if (!seconds) { + return knex.fn.now(); + } + + if (knex.client.config.client.includes('sqlite3')) { + return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]); + } + + if (knex.client.config.client.includes('mysql')) { + return knex.raw(`now() + interval ${seconds} second`); + } + + return knex.raw(`now() + interval '${seconds} seconds'`); +} + +/** + * Sleep for the given duration, but return sooner if the abort signal + * triggers. + * + * @param duration - The amount of time to sleep, at most + * @param abortSignal - An optional abort signal that short circuits the wait + */ +export async function sleep( + duration: Duration, + abortSignal?: AbortSignal, +): Promise { + if (abortSignal?.aborted) { + return; + } + + await new Promise(resolve => { + let timeoutHandle: NodeJS.Timeout | undefined = undefined; + + const done = () => { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + } + abortSignal?.removeEventListener('abort', done); + resolve(); + }; + + timeoutHandle = setTimeout(done, duration.as('milliseconds')); + abortSignal?.addEventListener('abort', done); + }); +} + +/** + * Creates a new AbortController that, in addition to working as a regular + * standalone controller, also gets aborted if the given parent signal + * reaches aborted state. + * + * @param parent - The "parent" signal that can trigger the delegate + */ +export function delegateAbortController(parent?: AbortSignal): AbortController { + const delegate = new AbortController(); + + if (parent) { + if (parent.aborted) { + delegate.abort(); + } else { + const onParentAborted = () => { + delegate.abort(); + }; + + const onChildAborted = () => { + parent.removeEventListener('abort', onParentAborted); + }; + + parent.addEventListener('abort', onParentAborted, { once: true }); + delegate.signal.addEventListener('abort', onChildAborted, { once: true }); + } + } + + return delegate; +} diff --git a/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.test.ts new file mode 100644 index 0000000000..7b889b3a0e --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { coreServices } from '@backstage/backend-plugin-api'; +import { ServiceFactoryTester } from '@backstage/backend-test-utils'; +import { schedulerServiceFactory } from './schedulerServiceFactory'; + +describe('schedulerFactory', () => { + it('creates sidecar database features', async () => { + const tester = ServiceFactoryTester.from(schedulerServiceFactory()); + + const scheduler = await tester.get(); + await scheduler.scheduleTask({ + id: 'task1', + timeout: { seconds: 1 }, + frequency: { seconds: 1 }, + fn: async () => {}, + }); + + const database = await tester.getService(coreServices.database); + + const client = await database.getClient(); + await expect( + client.from('backstage_backend_tasks__tasks').count(), + ).resolves.toEqual([{ 'count(*)': 1 }]); + await expect( + client.from('backstage_backend_tasks__knex_migrations').count(), + ).resolves.toEqual([{ 'count(*)': expect.any(Number) }]); + await expect( + client.from('backstage_backend_tasks__knex_migrations_lock').count(), + ).resolves.toEqual([{ 'count(*)': expect.any(Number) }]); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.ts b/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.ts new file mode 100644 index 0000000000..55c0d58e7b --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { TaskScheduler } from './lib/TaskScheduler'; + +/** + * The default service factory for {@link @backstage/backend-plugin-api#coreServices.scheduler}. + * + * @public + */ +export const schedulerServiceFactory = createServiceFactory({ + service: coreServices.scheduler, + deps: { + plugin: coreServices.pluginMetadata, + database: coreServices.database, + logger: coreServices.logger, + }, + async factory({ plugin, database, logger }) { + return TaskScheduler.forPlugin({ + pluginId: plugin.getId(), + databaseManager: database, + logger, + }); + }, +}); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/index.ts b/packages/backend-defaults/src/entrypoints/urlReader/index.ts new file mode 100644 index 0000000000..6a4b9f65be --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/urlReader/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 { urlReaderServiceFactory } from './urlReaderServiceFactory'; diff --git a/plugins/devtools-backend/src/run.ts b/packages/backend-defaults/src/entrypoints/urlReader/urlReaderServiceFactory.ts similarity index 53% rename from plugins/devtools-backend/src/run.ts rename to packages/backend-defaults/src/entrypoints/urlReader/urlReaderServiceFactory.ts index d945aa13f0..7f404a24b1 100644 --- a/plugins/devtools-backend/src/run.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/urlReaderServiceFactory.ts @@ -14,20 +14,23 @@ * limitations under the License. */ -import { getRootLogger } from '@backstage/backend-common'; -import yn from 'yn'; -import { startStandaloneServer } from './service/standaloneServer'; +import { UrlReaders } from '@backstage/backend-common'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; -const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007; -const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); -const logger = getRootLogger(); - -startStandaloneServer({ port, enableCors, logger }).catch(err => { - logger.error(err); - process.exit(1); -}); - -process.on('SIGINT', () => { - logger.info('CTRL+C pressed; exiting.'); - process.exit(0); +/** @public */ +export const urlReaderServiceFactory = createServiceFactory({ + service: coreServices.urlReader, + deps: { + config: coreServices.rootConfig, + logger: coreServices.logger, + }, + async factory({ config, logger }) { + return UrlReaders.default({ + config, + logger, + }); + }, }); diff --git a/plugins/auth-backend/src/run.ts b/packages/backend-defaults/src/setupTests.ts similarity index 62% rename from plugins/auth-backend/src/run.ts rename to packages/backend-defaults/src/setupTests.ts index 7732bbd41a..76619a2542 100644 --- a/plugins/auth-backend/src/run.ts +++ b/packages/backend-defaults/src/setupTests.ts @@ -14,19 +14,12 @@ * limitations under the License. */ -import { getRootLogger } from '@backstage/backend-common'; -import { startStandaloneServer } from './service/standaloneServer'; +import { TestDatabases } from '@backstage/backend-test-utils'; +import { Settings } from 'luxon'; -const logger = getRootLogger(); +// TS still thinks that methods can return null / placeholders, but we still want to throw as soon as possible when things go wrong +Settings.throwOnInvalid = true; -startStandaloneServer({ logger }).catch(err => { - logger.error(err); - process.exit(1); +TestDatabases.setDefaults({ + ids: ['MYSQL_8', 'POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], }); - -process.on('SIGINT', () => { - logger.info('CTRL+C pressed; exiting.'); - process.exit(0); -}); - -module.hot?.accept(); diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 95b6097025..2f8bb9f71b 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,102 @@ # @backstage/backend-dynamic-feature-service +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-events-backend@0.3.6-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-events-backend@0.3.6-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-scaffolder-node@0.4.5-next.0 + - @backstage/plugin-app-node@0.1.19-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-search-common@1.2.11 + +## 0.2.10 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- b611fd0: Updates the `scanRoot` method in the `PluginScanner` class to specifically ignore the `lost+found` directory, which is a system-generated directory used for file recovery on Unix-like systems. Skipping this directory avoids unnecessary errors. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-scaffolder-node@0.4.4 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-app-node@0.1.18 + - @backstage/plugin-events-backend@0.3.5 + - @backstage/plugin-permission-node@0.7.29 + +## 0.2.10-next.2 + +### Patch Changes + +- b192752: Updated `README.md` to point to `packages/backend` instead of `packages/backend-next`. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.22.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-scaffolder-node@0.4.4-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/plugin-scaffolder-node@0.4.4-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-events-backend@0.3.5-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/cli-node@0.2.5 + - @backstage/config-loader@1.8.0 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/plugin-app-node@0.1.18-next.1 + ## 0.2.10-next.0 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/README.md b/packages/backend-dynamic-feature-service/README.md index 211148ee10..a2f29b3d8f 100644 --- a/packages/backend-dynamic-feature-service/README.md +++ b/packages/backend-dynamic-feature-service/README.md @@ -10,7 +10,7 @@ In order to test the dynamic backend plugins feature provided by this package, e The dynamic plugin manager is a service that scans a configured root directory (`dynamicPlugins.rootDirectory` in the app config) for dynamic plugin packages, and loads them dynamically. -In the `backend-next` application, it can be enabled by adding the `backend-dynamic-feature-service` as a dependency in the `package.json` and the following lines in the `src/index.ts` file: +In the `backend` application, it can be enabled by adding the `backend-dynamic-feature-service` as a dependency in the `package.json` and the following lines in the `src/index.ts` file: ```ts const backend = createBackend(); diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 07a559c748..f9e4823f21 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.10-next.0", + "version": "0.2.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts index 487729687f..340991b11f 100644 --- a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts @@ -59,7 +59,7 @@ describe('backend-dynamic-feature-service', () => { name: string; packageManifest: ScannedPluginManifest; indexFile?: { - retativePath: string[]; + relativePath: string[]; content: string; }; expectedLogs?(location: URL): { @@ -83,7 +83,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ kind: "new", install: () => [] }', }, @@ -127,7 +127,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: `const alpha = { $$type: '@backstage/BackendFeature' }; exports["default"] = alpha;`, }, expectedLogs(location) { @@ -170,7 +170,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: `const alpha = () => { return { $$type: '@backstage/BackendFeature' } }; alpha.$$type = '@backstage/BackendFeatureFactory'; exports["default"] = alpha;`, @@ -215,7 +215,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ kind: "new", install: () => [] }', }, @@ -262,7 +262,7 @@ describe('backend-dynamic-feature-service', () => { return { errors: [ { - message: `an error occured while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + message: `an error occurred while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, meta: { name: 'Error', message: expect.stringContaining( @@ -305,7 +305,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: '', }, expectedLogs(location) { @@ -332,7 +332,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ something: "else", unexpectedMethod() {} }', }, @@ -360,14 +360,14 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'strange text with syntax error', }, expectedLogs(location) { return { errors: [ { - message: `an error occured while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + message: `an error occurred while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, meta: { message: expect.stringContaining('Unexpected identifier'), name: 'SyntaxError', @@ -391,7 +391,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ kind: "legacy", scaffolder: (env)=>[] }', }, @@ -458,7 +458,7 @@ describe('backend-dynamic-feature-service', () => { mockedFiles[ path.join( url.fileURLToPath(plugin.location), - ...tc.indexFile.retativePath, + ...tc.indexFile.relativePath, ) ] = tc.indexFile.content; } diff --git a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts index edc3e20f72..95b0c6592c 100644 --- a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts @@ -188,7 +188,7 @@ export class DynamicPluginManager implements DynamicPluginProvider { }; } catch (error) { this.logger.error( - `an error occured while loading dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`, + `an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`, error, ); return undefined; diff --git a/packages/backend-dynamic-feature-service/src/schemas/appBackendModule.ts b/packages/backend-dynamic-feature-service/src/schemas/appBackendModule.ts index b44913edfd..6e54379e90 100644 --- a/packages/backend-dynamic-feature-service/src/schemas/appBackendModule.ts +++ b/packages/backend-dynamic-feature-service/src/schemas/appBackendModule.ts @@ -17,13 +17,13 @@ import { coreServices, createBackendModule, + resolvePackagePath, } from '@backstage/backend-plugin-api'; import { dynamicPluginsSchemasServiceRef } from './schemas'; import { configSchemaExtensionPoint, loadCompiledConfigSchema, } from '@backstage/plugin-app-node'; -import { resolvePackagePath } from '@backstage/backend-common'; /** @public */ export const dynamicPluginsFrontendSchemas = createBackendModule({ diff --git a/packages/backend-next/.eslintrc.js b/packages/backend-legacy/.eslintrc.js similarity index 100% rename from packages/backend-next/.eslintrc.js rename to packages/backend-legacy/.eslintrc.js diff --git a/packages/backend-next/.snyk b/packages/backend-legacy/.snyk similarity index 100% rename from packages/backend-next/.snyk rename to packages/backend-legacy/.snyk diff --git a/packages/backend-legacy/CHANGELOG.md b/packages/backend-legacy/CHANGELOG.md new file mode 100644 index 0000000000..0484874683 --- /dev/null +++ b/packages/backend-legacy/CHANGELOG.md @@ -0,0 +1,7032 @@ +# example-backend-legacy + +## 0.2.99-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/plugin-search-backend@1.5.10-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.1 + - @backstage/plugin-kubernetes-backend@0.18.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/plugin-scaffolder-backend@1.22.8-next.1 + - @backstage/plugin-app-backend@0.3.68-next.1 + - @backstage/plugin-auth-backend@0.22.6-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.1 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/plugin-devtools-backend@0.3.5-next.1 + - @backstage/plugin-events-backend@0.3.6-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-permission-backend@0.5.43-next.1 + - @backstage/plugin-proxy-backend@0.5.0-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.20-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.36-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.2-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.28-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + - @backstage/plugin-signals-backend@0.1.5-next.1 + - @backstage/plugin-techdocs-backend@1.10.6-next.1 + - example-app@0.2.98-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.1 + - @backstage/plugin-signals-node@0.1.5-next.1 + +## 0.2.99-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-devtools-backend@0.3.5-next.0 + - @backstage/plugin-techdocs-backend@1.10.6-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-search-backend@1.5.10-next.0 + - @backstage/plugin-proxy-backend@0.5.0-next.0 + - @backstage/plugin-auth-backend@0.22.6-next.0 + - @backstage/plugin-app-backend@0.3.68-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.2-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.28-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/plugin-signals-backend@0.1.5-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/plugin-scaffolder-backend@1.22.8-next.0 + - @backstage/plugin-kubernetes-backend@0.17.2-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.0 + - example-app@0.2.98-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.0 + - @backstage/plugin-events-backend@0.3.6-next.0 + - @backstage/plugin-permission-backend@0.5.43-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.20-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.1-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.36-next.0 + - @backstage/plugin-signals-node@0.1.5-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.0 + - @backstage/plugin-catalog-node@1.12.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.11.0 + - @backstage/plugin-permission-common@0.7.13 + +## 0.2.98 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.4.1 + - @backstage/plugin-catalog-node@1.12.0 + - @backstage/plugin-scaffolder-backend@1.22.6 + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5 + - @backstage/plugin-search-backend-module-catalog@0.1.24 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-search-backend-module-pg@0.5.27 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-backend@0.22.5 + - @backstage/plugin-app-backend@0.3.66 + - @backstage/plugin-devtools-backend@0.3.4 + - @backstage/plugin-signals-backend@0.1.4 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/plugin-search-backend@1.5.8 + - @backstage/plugin-techdocs-backend@1.10.5 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-search-backend-module-explore@0.1.24 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/integration@1.11.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.23 + - example-app@0.2.97 + - @backstage/catalog-client@1.6.5 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16 + - @backstage/plugin-events-backend@0.3.5 + - @backstage/plugin-kubernetes-backend@0.17.1 + - @backstage/plugin-permission-backend@0.5.42 + - @backstage/plugin-permission-node@0.7.29 + - @backstage/plugin-proxy-backend@0.4.16 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.35 + - @backstage/plugin-signals-node@0.1.4 + +## 0.2.98-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.0-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.0-next.2 + - @backstage/plugin-catalog-backend@1.22.0-next.2 + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-devtools-backend@0.3.4-next.2 + - @backstage/plugin-scaffolder-backend@1.22.6-next.2 + - @backstage/plugin-signals-backend@0.1.4-next.2 + - @backstage/plugin-auth-backend@0.22.5-next.2 + - @backstage/plugin-techdocs-backend@1.10.5-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + - @backstage/integration@1.11.0-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.2 + - @backstage/plugin-kubernetes-backend@0.17.1-next.2 + - @backstage/plugin-search-backend@1.5.8-next.2 + - example-app@0.2.97-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.2 + +## 0.2.98-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.1 + - @backstage/plugin-scaffolder-backend@1.22.5-next.1 + - example-app@0.2.97-next.1 + - @backstage/plugin-search-backend@1.5.8-next.1 + - @backstage/plugin-app-backend@0.3.66-next.1 + - @backstage/plugin-kubernetes-backend@0.17.1-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-backend@0.22.5-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-devtools-backend@0.3.4-next.1 + - @backstage/plugin-events-backend@0.3.5-next.1 + - @backstage/plugin-events-node@0.3.4-next.1 + - @backstage/plugin-permission-backend@0.5.42-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-proxy-backend@0.4.16-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.4-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.1-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.24-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.27-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/plugin-signals-backend@0.1.4-next.1 + - @backstage/plugin-signals-node@0.1.4-next.1 + - @backstage/plugin-techdocs-backend@1.10.5-next.1 + - @backstage/plugin-catalog-node@1.11.2-next.1 + +## 0.2.98-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.22.0-next.0 + - @backstage/plugin-scaffolder-backend@1.22.5-next.0 + - @backstage/catalog-model@1.5.0-next.0 + - @backstage/plugin-search-backend-node@1.2.22-next.0 + - @backstage/plugin-search-backend@1.5.8-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.4-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.23-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.23-next.0 + - @backstage/plugin-auth-backend@0.22.5-next.0 + - @backstage/plugin-auth-node@0.4.13-next.0 + - @backstage/backend-common@0.21.8-next.0 + - example-app@0.2.97-next.0 + - @backstage/plugin-app-backend@0.3.66-next.0 + - @backstage/plugin-kubernetes-backend@0.17.1-next.0 + - @backstage/catalog-client@1.6.5-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.0 + - @backstage/plugin-catalog-node@1.11.2-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.0 + - @backstage/plugin-techdocs-backend@1.10.5-next.0 + - @backstage/backend-tasks@0.5.23-next.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.10.0 + - @backstage/plugin-devtools-backend@0.3.4-next.0 + - @backstage/plugin-events-backend@0.3.5-next.0 + - @backstage/plugin-events-node@0.3.4-next.0 + - @backstage/plugin-permission-backend@0.5.42-next.0 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-permission-node@0.7.29-next.0 + - @backstage/plugin-proxy-backend@0.4.16-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.1-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.27-next.0 + - @backstage/plugin-signals-backend@0.1.4-next.0 + - @backstage/plugin-signals-node@0.1.4-next.0 + +## 0.2.97 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-pg@0.5.26 + - @backstage/plugin-badges-backend@0.4.0 + - @backstage/plugin-kubernetes-backend@0.17.0 + - @backstage/backend-common@0.21.7 + - @backstage/plugin-azure-devops-backend@0.6.4 + - @backstage/plugin-techdocs-backend@1.10.4 + - @backstage/plugin-permission-node@0.7.28 + - @backstage/plugin-auth-backend@0.22.4 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.3 + - @backstage/plugin-catalog-backend@1.21.1 + - @backstage/plugin-events-backend@0.3.4 + - @backstage/plugin-tech-insights-node@0.6.0 + - @backstage/plugin-search-backend@1.5.7 + - @backstage/plugin-todo-backend@0.3.16 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.49 + - @backstage/plugin-search-backend-module-techdocs@0.1.22 + - @backstage/plugin-search-backend-module-explore@0.1.21 + - @backstage/plugin-entity-feedback-backend@0.2.14 + - @backstage/plugin-code-coverage-backend@0.2.31 + - @backstage/plugin-tech-insights-backend@0.5.31 + - @backstage/plugin-search-backend-node@1.2.21 + - @backstage/plugin-lighthouse-backend@0.4.10 + - @backstage/plugin-permission-backend@0.5.41 + - @backstage/plugin-devtools-backend@0.3.3 + - @backstage/plugin-linguist-backend@0.5.15 + - @backstage/plugin-playlist-backend@0.3.21 + - @backstage/plugin-explore-backend@0.0.27 + - @backstage/plugin-jenkins-backend@0.4.4 + - @backstage/backend-tasks@0.5.22 + - @backstage/plugin-kafka-backend@0.3.15 + - @backstage/plugin-nomad-backend@0.1.19 + - @backstage/plugin-adr-backend@0.4.14 + - @backstage/plugin-app-backend@0.3.65 + - @backstage/plugin-auth-node@0.4.12 + - @backstage/plugin-signals-backend@0.1.3 + - @backstage/plugin-proxy-backend@0.4.15 + - @backstage/plugin-scaffolder-backend@1.22.4 + - @backstage/catalog-client@1.6.4 + - @backstage/integration@1.10.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.4.0 + - example-app@0.2.96 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4 + - @backstage/plugin-events-node@0.3.3 + - @backstage/plugin-rollbar-backend@0.1.62 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.18 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.34 + - @backstage/plugin-search-backend-module-catalog@0.1.22 + - @backstage/plugin-signals-node@0.1.3 + - @backstage/plugin-catalog-node@1.11.1 + - @backstage/catalog-model@1.4.5 + - @backstage/config@1.2.0 + - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15 + - @backstage/plugin-permission-common@0.7.13 + +## 0.2.97-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.17.0-next.1 + - @backstage/backend-common@0.21.7-next.1 + - @backstage/plugin-azure-devops-backend@0.6.4-next.1 + - @backstage/plugin-techdocs-backend@1.10.4-next.1 + - @backstage/plugin-events-backend@0.3.4-next.1 + - @backstage/plugin-auth-backend@0.22.4-next.1 + - @backstage/plugin-auth-node@0.4.12-next.1 + - @backstage/plugin-proxy-backend@0.4.15-next.1 + - @backstage/plugin-scaffolder-backend@1.22.4-next.1 + - @backstage/plugin-catalog-backend@1.21.1-next.1 + - @backstage/catalog-client@1.6.4-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.3-next.1 + - @backstage/plugin-app-backend@0.3.65-next.1 + - @backstage/backend-tasks@0.5.22-next.1 + - @backstage/plugin-adr-backend@0.4.14-next.1 + - @backstage/plugin-badges-backend@0.3.14-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4-next.1 + - @backstage/plugin-code-coverage-backend@0.2.31-next.1 + - @backstage/plugin-devtools-backend@0.3.3-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.14-next.1 + - @backstage/plugin-events-node@0.3.3-next.1 + - @backstage/plugin-explore-backend@0.0.27-next.1 + - @backstage/plugin-jenkins-backend@0.4.4-next.1 + - @backstage/plugin-kafka-backend@0.3.15-next.1 + - @backstage/plugin-lighthouse-backend@0.4.10-next.1 + - @backstage/plugin-linguist-backend@0.5.15-next.1 + - @backstage/plugin-nomad-backend@0.1.19-next.1 + - @backstage/plugin-permission-backend@0.5.41-next.1 + - @backstage/plugin-permission-node@0.7.28-next.1 + - @backstage/plugin-playlist-backend@0.3.21-next.1 + - @backstage/plugin-rollbar-backend@0.1.62-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.18-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.34-next.1 + - @backstage/plugin-search-backend@1.5.7-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.22-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.20-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.21-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.26-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.22-next.1 + - @backstage/plugin-search-backend-node@1.2.21-next.1 + - @backstage/plugin-signals-backend@0.1.3-next.1 + - @backstage/plugin-signals-node@0.1.3-next.1 + - @backstage/plugin-tech-insights-backend@0.5.31-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.49-next.1 + - @backstage/plugin-tech-insights-node@0.5.3-next.1 + - @backstage/plugin-todo-backend@0.3.16-next.1 + - example-app@0.2.96-next.1 + - @backstage/catalog-model@1.4.5 + - @backstage/config@1.2.0 + - @backstage/integration@1.10.0-next.0 + - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15-next.1 + - @backstage/plugin-catalog-node@1.11.1-next.1 + - @backstage/plugin-permission-common@0.7.13 + +## 0.2.97-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.10.4-next.0 + - @backstage/plugin-catalog-backend@1.21.1-next.0 + - @backstage/plugin-kubernetes-backend@0.16.4-next.0 + - @backstage/plugin-signals-backend@0.1.3-next.0 + - @backstage/backend-common@0.21.7-next.0 + - @backstage/integration@1.10.0-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.22-next.0 + - @backstage/plugin-scaffolder-backend@1.22.4-next.0 + - @backstage/plugin-app-backend@0.3.65-next.0 + - example-app@0.2.96-next.0 + - @backstage/backend-tasks@0.5.22-next.0 + - @backstage/catalog-client@1.6.3 + - @backstage/catalog-model@1.4.5 + - @backstage/config@1.2.0 + - @backstage/plugin-adr-backend@0.4.14-next.0 + - @backstage/plugin-auth-backend@0.22.4-next.0 + - @backstage/plugin-auth-node@0.4.12-next.0 + - @backstage/plugin-azure-devops-backend@0.6.4-next.0 + - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-badges-backend@0.3.14-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4-next.0 + - @backstage/plugin-catalog-node@1.11.1-next.0 + - @backstage/plugin-code-coverage-backend@0.2.31-next.0 + - @backstage/plugin-devtools-backend@0.3.3-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.14-next.0 + - @backstage/plugin-events-backend@0.3.3-next.0 + - @backstage/plugin-events-node@0.3.3-next.0 + - @backstage/plugin-explore-backend@0.0.27-next.0 + - @backstage/plugin-jenkins-backend@0.4.4-next.0 + - @backstage/plugin-kafka-backend@0.3.15-next.0 + - @backstage/plugin-lighthouse-backend@0.4.10-next.0 + - @backstage/plugin-linguist-backend@0.5.15-next.0 + - @backstage/plugin-nomad-backend@0.1.19-next.0 + - @backstage/plugin-permission-backend@0.5.41-next.0 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-permission-node@0.7.28-next.0 + - @backstage/plugin-playlist-backend@0.3.21-next.0 + - @backstage/plugin-proxy-backend@0.4.15-next.0 + - @backstage/plugin-rollbar-backend@0.1.62-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.18-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.3-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.34-next.0 + - @backstage/plugin-search-backend@1.5.7-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.22-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.20-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.21-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.26-next.0 + - @backstage/plugin-search-backend-node@1.2.21-next.0 + - @backstage/plugin-signals-node@0.1.3-next.0 + - @backstage/plugin-tech-insights-backend@0.5.31-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.49-next.0 + - @backstage/plugin-tech-insights-node@0.5.3-next.0 + - @backstage/plugin-todo-backend@0.3.16-next.0 + +## 0.2.96 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.21.0 + - @backstage/plugin-catalog-node@1.11.0 + - @backstage/plugin-kubernetes-backend@0.16.3 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.3 + - @backstage/plugin-permission-backend@0.5.40 + - @backstage/plugin-proxy-backend@0.4.14 + - @backstage/plugin-scaffolder-backend@1.22.3 + - @backstage/catalog-client@1.6.3 + - @backstage/plugin-jenkins-backend@0.4.3 + - @backstage/plugin-auth-backend@0.22.3 + - @backstage/plugin-auth-node@0.4.11 + - @backstage/backend-common@0.21.6 + - @backstage/plugin-azure-devops-backend@0.6.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.14 + - @backstage/plugin-lighthouse-backend@0.4.9 + - @backstage/plugin-linguist-backend@0.5.14 + - @backstage/plugin-search-backend-module-catalog@0.1.21 + - @backstage/plugin-search-backend-module-techdocs@0.1.21 + - @backstage/plugin-todo-backend@0.3.15 + - example-app@0.2.95 + - @backstage/plugin-app-backend@0.3.64 + - @backstage/plugin-adr-backend@0.4.13 + - @backstage/plugin-badges-backend@0.3.13 + - @backstage/plugin-code-coverage-backend@0.2.30 + - @backstage/plugin-entity-feedback-backend@0.2.13 + - @backstage/plugin-playlist-backend@0.3.20 + - @backstage/plugin-tech-insights-backend@0.5.30 + - @backstage/plugin-techdocs-backend@1.10.3 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.2 + - @backstage/plugin-permission-node@0.7.27 + - @backstage/plugin-signals-backend@0.1.2 + - @backstage/plugin-signals-node@0.1.2 + - @backstage/backend-tasks@0.5.21 + - @backstage/plugin-devtools-backend@0.3.2 + - @backstage/plugin-events-backend@0.3.2 + - @backstage/plugin-events-node@0.3.2 + - @backstage/plugin-explore-backend@0.0.26 + - @backstage/plugin-kafka-backend@0.3.14 + - @backstage/plugin-nomad-backend@0.1.18 + - @backstage/plugin-rollbar-backend@0.1.61 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.17 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.33 + - @backstage/plugin-search-backend@1.5.6 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.19 + - @backstage/plugin-search-backend-module-explore@0.1.20 + - @backstage/plugin-search-backend-module-pg@0.5.25 + - @backstage/plugin-search-backend-node@1.2.20 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.48 + - @backstage/plugin-tech-insights-node@0.5.2 + - @backstage/catalog-model@1.4.5 + - @backstage/config@1.2.0 + - @backstage/integration@1.9.1 + - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-permission-common@0.7.13 + +## 0.2.95 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.20.0 + - @backstage/plugin-catalog-node@1.10.0 + - @backstage/plugin-kubernetes-backend@0.16.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.2 + - @backstage/plugin-permission-backend@0.5.39 + - @backstage/catalog-client@1.6.2 + - @backstage/backend-common@0.21.5 + - @backstage/plugin-auth-backend@0.22.2 + - @backstage/plugin-azure-devops-backend@0.6.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.13 + - @backstage/plugin-jenkins-backend@0.4.2 + - @backstage/plugin-lighthouse-backend@0.4.8 + - @backstage/plugin-linguist-backend@0.5.13 + - @backstage/plugin-scaffolder-backend@1.22.2 + - @backstage/plugin-search-backend-module-catalog@0.1.20 + - @backstage/plugin-search-backend-module-techdocs@0.1.20 + - @backstage/plugin-todo-backend@0.3.14 + - example-app@0.2.94 + - @backstage/plugin-app-backend@0.3.63 + - @backstage/plugin-adr-backend@0.4.12 + - @backstage/plugin-auth-node@0.4.10 + - @backstage/plugin-badges-backend@0.3.12 + - @backstage/plugin-code-coverage-backend@0.2.29 + - @backstage/plugin-entity-feedback-backend@0.2.12 + - @backstage/plugin-playlist-backend@0.3.19 + - @backstage/plugin-tech-insights-backend@0.5.29 + - @backstage/plugin-techdocs-backend@1.10.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.1 + - @backstage/backend-tasks@0.5.20 + - @backstage/plugin-devtools-backend@0.3.1 + - @backstage/plugin-events-backend@0.3.1 + - @backstage/plugin-events-node@0.3.1 + - @backstage/plugin-explore-backend@0.0.25 + - @backstage/plugin-kafka-backend@0.3.13 + - @backstage/plugin-nomad-backend@0.1.17 + - @backstage/plugin-permission-node@0.7.26 + - @backstage/plugin-proxy-backend@0.4.13 + - @backstage/plugin-rollbar-backend@0.1.60 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.16 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.32 + - @backstage/plugin-search-backend@1.5.5 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.18 + - @backstage/plugin-search-backend-module-explore@0.1.19 + - @backstage/plugin-search-backend-module-pg@0.5.24 + - @backstage/plugin-search-backend-node@1.2.19 + - @backstage/plugin-signals-backend@0.1.1 + - @backstage/plugin-signals-node@0.1.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.47 + - @backstage/plugin-tech-insights-node@0.5.1 + - @backstage/catalog-model@1.4.5 + - @backstage/config@1.2.0 + - @backstage/integration@1.9.1 + - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-permission-common@0.7.13 + +## 0.2.94 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.19.0 + - @backstage/plugin-catalog-node@1.9.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.1 + - @backstage/plugin-permission-backend@0.5.38 + - @backstage/plugin-auth-backend@0.22.1 + - @backstage/plugin-azure-devops-backend@0.6.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.12 + - @backstage/plugin-jenkins-backend@0.4.1 + - @backstage/plugin-kubernetes-backend@0.16.1 + - @backstage/plugin-lighthouse-backend@0.4.7 + - @backstage/plugin-linguist-backend@0.5.12 + - @backstage/plugin-scaffolder-backend@1.22.1 + - @backstage/plugin-search-backend-module-catalog@0.1.19 + - @backstage/plugin-search-backend-module-techdocs@0.1.19 + - @backstage/plugin-todo-backend@0.3.13 + - @backstage/plugin-techdocs-backend@1.10.1 + +## 0.2.93 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-backend@0.3.0 + - @backstage/plugin-events-node@0.3.0 + - @backstage/plugin-scaffolder-backend@1.22.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.31 + - @backstage/plugin-linguist-backend@0.5.11 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.0 + - @backstage/plugin-catalog-backend@1.18.0 + - @backstage/plugin-code-coverage-backend@0.2.28 + - @backstage/plugin-devtools-backend@0.3.0 + - @backstage/plugin-jenkins-backend@0.4.0 + - @backstage/plugin-search-backend@1.5.4 + - @backstage/backend-common@0.21.4 + - @backstage/integration@1.9.1 + - @backstage/plugin-auth-node@0.4.9 + - @backstage/plugin-lighthouse-backend@0.4.6 + - @backstage/config@1.2.0 + - @backstage/plugin-azure-devops-backend@0.6.0 + - @backstage/plugin-permission-backend@0.5.37 + - @backstage/plugin-signals-backend@0.1.0 + - @backstage/plugin-nomad-backend@0.1.16 + - @backstage/plugin-entity-feedback-backend@0.2.11 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.17 + - @backstage/plugin-search-backend-module-pg@0.5.23 + - @backstage/plugin-signals-node@0.1.0 + - @backstage/plugin-playlist-backend@0.3.18 + - @backstage/plugin-auth-backend@0.22.0 + - @backstage/plugin-techdocs-backend@1.10.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.15 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.0 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-search-backend-module-techdocs@0.1.18 + - @backstage/plugin-search-backend-module-catalog@0.1.18 + - @backstage/plugin-search-backend-module-explore@0.1.18 + - @backstage/plugin-catalog-node@1.8.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.46 + - @backstage/catalog-client@1.6.1 + - @backstage/plugin-kubernetes-backend@0.16.0 + - @backstage/plugin-adr-backend@0.4.11 + - @backstage/plugin-proxy-backend@0.4.12 + - @backstage/backend-tasks@0.5.19 + - @backstage/plugin-search-backend-node@1.2.18 + - @backstage/plugin-tech-insights-backend@0.5.28 + - @backstage/plugin-app-backend@0.3.62 + - @backstage/plugin-permission-node@0.7.25 + - @backstage/plugin-todo-backend@0.3.12 + - @backstage/plugin-tech-insights-node@0.5.0 + - @backstage/plugin-badges-backend@0.3.11 + - example-app@0.2.93 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11 + - @backstage/plugin-explore-backend@0.0.24 + - @backstage/plugin-rollbar-backend@0.1.59 + - @backstage/plugin-kafka-backend@0.3.12 + - @backstage/catalog-model@1.4.5 + - @backstage/plugin-azure-sites-common@0.1.3 + +## 0.2.93-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.22.0-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.31-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.11-next.2 + - @backstage/plugin-catalog-backend@1.18.0-next.2 + - @backstage/plugin-code-coverage-backend@0.2.28-next.2 + - @backstage/plugin-devtools-backend@0.3.0-next.2 + - @backstage/plugin-jenkins-backend@0.4.0-next.2 + - @backstage/plugin-search-backend@1.5.4-next.2 + - @backstage/integration@1.9.1-next.2 + - @backstage/plugin-techdocs-backend@1.10.0-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.0-next.2 + - @backstage/plugin-signals-node@0.1.0-next.2 + - @backstage/catalog-client@1.6.1-next.1 + - @backstage/plugin-linguist-backend@0.5.11-next.2 + - @backstage/plugin-kubernetes-backend@0.16.0-next.2 + - @backstage/plugin-todo-backend@0.3.12-next.2 + - @backstage/plugin-signals-backend@0.1.0-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.15-next.2 + - @backstage/backend-common@0.21.4-next.2 + - @backstage/plugin-adr-backend@0.4.11-next.2 + - @backstage/plugin-azure-devops-backend@0.6.0-next.2 + - example-app@0.2.93-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.18-next.2 + - @backstage/plugin-auth-backend@0.22.0-next.2 + - @backstage/plugin-app-backend@0.3.62-next.2 + - @backstage/plugin-auth-node@0.4.9-next.2 + - @backstage/plugin-badges-backend@0.3.11-next.2 + - @backstage/plugin-catalog-node@1.8.0-next.2 + - @backstage/plugin-entity-feedback-backend@0.2.11-next.2 + - @backstage/plugin-lighthouse-backend@0.4.6-next.2 + - @backstage/plugin-playlist-backend@0.3.18-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.18-next.2 + - @backstage/plugin-tech-insights-backend@0.5.28-next.2 + - @backstage/backend-tasks@0.5.19-next.2 + - @backstage/catalog-model@1.4.5-next.0 + - @backstage/config@1.2.0-next.1 + - @backstage/plugin-azure-sites-common@0.1.3-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11-next.2 + - @backstage/plugin-events-backend@0.3.0-next.2 + - @backstage/plugin-events-node@0.3.0-next.2 + - @backstage/plugin-explore-backend@0.0.24-next.2 + - @backstage/plugin-kafka-backend@0.3.12-next.2 + - @backstage/plugin-nomad-backend@0.1.16-next.2 + - @backstage/plugin-permission-backend@0.5.37-next.2 + - @backstage/plugin-permission-common@0.7.13-next.1 + - @backstage/plugin-permission-node@0.7.25-next.2 + - @backstage/plugin-proxy-backend@0.4.12-next.2 + - @backstage/plugin-rollbar-backend@0.1.59-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.17-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.18-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.23-next.2 + - @backstage/plugin-search-backend-node@1.2.18-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.46-next.2 + - @backstage/plugin-tech-insights-node@0.5.0-next.2 + +## 0.2.93-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.2.0-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend@1.22.0-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.17-next.1 + - @backstage/plugin-app-backend@0.3.62-next.1 + - @backstage/plugin-signals-backend@0.1.0-next.1 + - @backstage/plugin-signals-node@0.1.0-next.1 + - @backstage/plugin-azure-devops-backend@0.6.0-next.1 + - @backstage/plugin-kubernetes-backend@0.16.0-next.1 + - example-app@0.2.93-next.1 + - @backstage/backend-common@0.21.4-next.1 + - @backstage/backend-tasks@0.5.19-next.1 + - @backstage/integration@1.9.1-next.1 + - @backstage/plugin-adr-backend@0.4.11-next.1 + - @backstage/plugin-auth-backend@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.9-next.1 + - @backstage/plugin-badges-backend@0.3.11-next.1 + - @backstage/plugin-catalog-backend@1.18.0-next.1 + - @backstage/plugin-code-coverage-backend@0.2.28-next.1 + - @backstage/plugin-devtools-backend@0.3.0-next.1 + - @backstage/plugin-events-backend@0.3.0-next.1 + - @backstage/plugin-explore-backend@0.0.24-next.1 + - @backstage/plugin-jenkins-backend@0.4.0-next.1 + - @backstage/plugin-kafka-backend@0.3.12-next.1 + - @backstage/plugin-lighthouse-backend@0.4.6-next.1 + - @backstage/plugin-linguist-backend@0.5.11-next.1 + - @backstage/plugin-nomad-backend@0.1.16-next.1 + - @backstage/plugin-permission-backend@0.5.37-next.1 + - @backstage/plugin-permission-common@0.7.13-next.1 + - @backstage/plugin-permission-node@0.7.25-next.1 + - @backstage/plugin-playlist-backend@0.3.18-next.1 + - @backstage/plugin-proxy-backend@0.4.12-next.1 + - @backstage/plugin-rollbar-backend@0.1.59-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.15-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.17-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.31-next.1 + - @backstage/plugin-search-backend@1.5.4-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.18-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.18-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.23-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.18-next.1 + - @backstage/plugin-search-backend-node@1.2.18-next.1 + - @backstage/plugin-tech-insights-backend@0.5.28-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.46-next.1 + - @backstage/plugin-tech-insights-node@0.5.0-next.1 + - @backstage/plugin-techdocs-backend@1.9.7-next.1 + - @backstage/plugin-todo-backend@0.3.12-next.1 + - @backstage/catalog-client@1.6.1-next.0 + - @backstage/catalog-model@1.4.5-next.0 + - @backstage/plugin-azure-sites-common@0.1.3-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.11-next.1 + - @backstage/plugin-catalog-node@1.8.0-next.1 + - @backstage/plugin-events-node@0.3.0-next.1 + +## 0.2.93-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-backend@0.3.0-next.0 + - @backstage/plugin-events-node@0.3.0-next.0 + - @backstage/plugin-linguist-backend@0.5.10-next.0 + - @backstage/backend-common@0.21.3-next.0 + - @backstage/plugin-auth-node@0.4.8-next.0 + - @backstage/plugin-lighthouse-backend@0.4.5-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.16-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.22-next.0 + - @backstage/plugin-playlist-backend@0.3.17-next.0 + - @backstage/plugin-code-coverage-backend@0.2.27-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.10-next.0 + - @backstage/plugin-catalog-backend@1.18.0-next.0 + - @backstage/plugin-auth-backend@0.22.0-next.0 + - @backstage/plugin-jenkins-backend@0.4.0-next.0 + - @backstage/plugin-azure-devops-backend@0.6.0-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.14-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.16-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.30-next.0 + - @backstage/plugin-scaffolder-backend@1.22.0-next.0 + - @backstage/plugin-permission-common@0.7.13-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.17-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.17-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.17-next.0 + - @backstage/plugin-catalog-node@1.8.0-next.0 + - @backstage/plugin-kubernetes-backend@0.16.0-next.0 + - @backstage/plugin-adr-backend@0.4.10-next.0 + - @backstage/plugin-proxy-backend@0.4.11-next.0 + - @backstage/backend-tasks@0.5.18-next.0 + - @backstage/plugin-search-backend-node@1.2.17-next.0 + - @backstage/plugin-signals-backend@0.0.4-next.0 + - @backstage/plugin-signals-node@0.0.4-next.0 + - @backstage/plugin-tech-insights-backend@0.5.27-next.0 + - @backstage/plugin-search-backend@1.5.3-next.0 + - @backstage/plugin-devtools-backend@0.3.0-next.0 + - @backstage/plugin-permission-node@0.7.24-next.0 + - @backstage/plugin-tech-insights-node@0.5.0-next.0 + - @backstage/plugin-badges-backend@0.3.10-next.0 + - @backstage/plugin-permission-backend@0.5.36-next.0 + - @backstage/plugin-app-backend@0.3.61-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.10-next.0 + - @backstage/plugin-explore-backend@0.0.23-next.0 + - @backstage/plugin-rollbar-backend@0.1.58-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.45-next.0 + - @backstage/plugin-techdocs-backend@1.9.6-next.0 + - @backstage/plugin-kafka-backend@0.3.11-next.0 + - @backstage/plugin-nomad-backend@0.1.15-next.0 + - @backstage/plugin-todo-backend@0.3.11-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.10-next.0 + - example-app@0.2.93-next.0 + - @backstage/catalog-client@1.6.1-next.0 + - @backstage/catalog-model@1.4.5-next.0 + - @backstage/config@1.1.2-next.0 + - @backstage/integration@1.9.1-next.0 + - @backstage/plugin-azure-sites-common@0.1.3-next.0 + +## 0.2.92 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.21.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.27 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7 + - @backstage/plugin-scaffolder-backend@1.21.0 + - @backstage/plugin-badges-backend@0.3.7 + - @backstage/plugin-azure-devops-backend@0.5.2 + - @backstage/plugin-explore-backend@0.0.20 + - @backstage/plugin-auth-backend@0.21.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42 + - @backstage/plugin-auth-node@0.4.4 + - @backstage/plugin-entity-feedback-backend@0.2.7 + - @backstage/plugin-lighthouse-backend@0.4.2 + - @backstage/plugin-devtools-backend@0.2.7 + - @backstage/plugin-linguist-backend@0.5.7 + - @backstage/plugin-adr-backend@0.4.7 + - @backstage/plugin-kubernetes-backend@0.15.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.13 + - @backstage/plugin-signals-backend@0.0.1 + - @backstage/plugin-signals-node@0.0.1 + - @backstage/plugin-tech-insights-backend@0.5.24 + - @backstage/plugin-tech-insights-node@0.4.16 + - @backstage/plugin-search-backend-module-techdocs@0.1.14 + - @backstage/plugin-search-backend-module-catalog@0.1.14 + - @backstage/plugin-search-backend-module-explore@0.1.14 + - @backstage/plugin-code-coverage-backend@0.2.24 + - @backstage/plugin-playlist-backend@0.3.14 + - @backstage/plugin-catalog-backend@1.17.0 + - @backstage/plugin-jenkins-backend@0.3.4 + - @backstage/plugin-rollbar-backend@0.1.55 + - @backstage/backend-tasks@0.5.15 + - @backstage/plugin-events-backend@0.2.19 + - @backstage/plugin-nomad-backend@0.1.12 + - @backstage/plugin-app-backend@0.3.58 + - @backstage/catalog-model@1.4.4 + - @backstage/integration@1.9.0 + - @backstage/catalog-client@1.6.0 + - @backstage/plugin-search-backend@1.5.0 + - @backstage/plugin-todo-backend@0.3.8 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7 + - @backstage/plugin-techdocs-backend@1.9.3 + - @backstage/plugin-catalog-node@1.7.0 + - @backstage/plugin-azure-sites-common@0.1.2 + - example-app@0.2.92 + - @backstage/plugin-kafka-backend@0.3.8 + - @backstage/plugin-permission-backend@0.5.33 + - @backstage/plugin-permission-node@0.7.21 + - @backstage/plugin-proxy-backend@0.4.8 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.13 + - @backstage/plugin-search-backend-module-pg@0.5.19 + - @backstage/plugin-search-backend-node@1.2.14 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-common@1.2.10 + +## 0.2.92-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.21.0-next.3 + - @backstage/plugin-badges-backend@0.3.7-next.3 + - @backstage/plugin-kubernetes-backend@0.15.0-next.3 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.13-next.3 + - @backstage/integration@1.9.0-next.1 + - @backstage/backend-tasks@0.5.15-next.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.3 + - @backstage/plugin-signals-backend@0.0.1-next.3 + - @backstage/plugin-signals-node@0.0.1-next.3 + - @backstage/plugin-catalog-backend@1.17.0-next.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.3 + - @backstage/plugin-app-backend@0.3.58-next.3 + - @backstage/plugin-auth-backend@0.21.0-next.3 + - @backstage/plugin-catalog-node@1.6.2-next.3 + - @backstage/plugin-adr-backend@0.4.7-next.3 + - @backstage/plugin-auth-node@0.4.4-next.3 + - @backstage/plugin-azure-devops-backend@0.5.2-next.3 + - @backstage/plugin-code-coverage-backend@0.2.24-next.3 + - @backstage/plugin-devtools-backend@0.2.7-next.3 + - @backstage/plugin-entity-feedback-backend@0.2.7-next.3 + - @backstage/plugin-events-backend@0.2.19-next.3 + - @backstage/plugin-explore-backend@0.0.20-next.3 + - @backstage/plugin-jenkins-backend@0.3.4-next.3 + - @backstage/plugin-kafka-backend@0.3.8-next.3 + - @backstage/plugin-lighthouse-backend@0.4.2-next.3 + - @backstage/plugin-linguist-backend@0.5.7-next.3 + - @backstage/plugin-nomad-backend@0.1.12-next.3 + - @backstage/plugin-permission-backend@0.5.33-next.3 + - @backstage/plugin-permission-node@0.7.21-next.3 + - @backstage/plugin-playlist-backend@0.3.14-next.3 + - @backstage/plugin-proxy-backend@0.4.8-next.3 + - @backstage/plugin-rollbar-backend@0.1.55-next.3 + - @backstage/plugin-scaffolder-backend@1.21.0-next.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.3 + - @backstage/plugin-search-backend@1.5.0-next.3 + - @backstage/plugin-search-backend-module-catalog@0.1.14-next.3 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.3 + - @backstage/plugin-search-backend-module-explore@0.1.14-next.3 + - @backstage/plugin-search-backend-module-pg@0.5.19-next.3 + - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.3 + - @backstage/plugin-search-backend-node@1.2.14-next.3 + - @backstage/plugin-tech-insights-backend@0.5.24-next.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.3 + - @backstage/plugin-tech-insights-node@0.4.16-next.3 + - @backstage/plugin-techdocs-backend@1.9.3-next.3 + - @backstage/plugin-todo-backend@0.3.8-next.3 + - example-app@0.2.92-next.3 + - @backstage/catalog-client@1.6.0-next.1 + - @backstage/catalog-model@1.4.4-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.2-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.3 + - @backstage/plugin-events-node@0.2.19-next.3 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-common@1.2.10 + +## 0.2.92-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.21.0-next.2 + - @backstage/plugin-auth-backend@0.21.0-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.2 + - @backstage/backend-common@0.21.0-next.2 + - @backstage/plugin-signals-backend@0.0.1-next.2 + - @backstage/plugin-signals-node@0.0.1-next.2 + - @backstage/plugin-kubernetes-backend@0.15.0-next.2 + - @backstage/plugin-tech-insights-backend@0.5.24-next.2 + - @backstage/plugin-tech-insights-node@0.4.16-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.14-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.14-next.2 + - @backstage/plugin-entity-feedback-backend@0.2.7-next.2 + - @backstage/plugin-code-coverage-backend@0.2.24-next.2 + - @backstage/plugin-azure-devops-backend@0.5.2-next.2 + - @backstage/plugin-lighthouse-backend@0.4.2-next.2 + - @backstage/plugin-devtools-backend@0.2.7-next.2 + - @backstage/plugin-linguist-backend@0.5.7-next.2 + - @backstage/plugin-playlist-backend@0.3.14-next.2 + - @backstage/plugin-catalog-backend@1.17.0-next.2 + - @backstage/plugin-explore-backend@0.0.20-next.2 + - @backstage/plugin-jenkins-backend@0.3.4-next.2 + - @backstage/plugin-rollbar-backend@0.1.55-next.2 + - @backstage/backend-tasks@0.5.15-next.2 + - @backstage/plugin-badges-backend@0.3.7-next.2 + - @backstage/plugin-events-backend@0.2.19-next.2 + - @backstage/plugin-nomad-backend@0.1.12-next.2 + - @backstage/plugin-adr-backend@0.4.7-next.2 + - @backstage/plugin-app-backend@0.3.58-next.2 + - @backstage/plugin-auth-node@0.4.4-next.2 + - example-app@0.2.92-next.2 + - @backstage/plugin-todo-backend@0.3.8-next.2 + - @backstage/plugin-kafka-backend@0.3.8-next.2 + - @backstage/plugin-permission-backend@0.5.33-next.2 + - @backstage/plugin-permission-node@0.7.21-next.2 + - @backstage/plugin-proxy-backend@0.4.8-next.2 + - @backstage/plugin-search-backend@1.5.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.19-next.2 + - @backstage/plugin-search-backend-node@1.2.14-next.2 + - @backstage/plugin-techdocs-backend@1.9.3-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.2 + - @backstage/plugin-catalog-node@1.6.2-next.2 + - @backstage/plugin-events-node@0.2.19-next.2 + - @backstage/config@1.1.1 + - @backstage/catalog-client@1.6.0-next.1 + - @backstage/catalog-model@1.4.4-next.0 + - @backstage/integration@1.9.0-next.0 + - @backstage/plugin-azure-sites-common@0.1.2-next.0 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-common@1.2.10 + +## 0.2.92-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.21.0-next.1 + - @backstage/plugin-azure-devops-backend@0.5.2-next.1 + - @backstage/catalog-model@1.4.4-next.0 + - @backstage/catalog-client@1.6.0-next.1 + - @backstage/plugin-catalog-backend@1.17.0-next.1 + - @backstage/backend-common@0.21.0-next.1 + - @backstage/plugin-auth-backend@0.20.4-next.1 + - @backstage/integration@1.9.0-next.0 + - @backstage/plugin-azure-sites-common@0.1.2-next.0 + - example-app@0.2.92-next.1 + - @backstage/backend-tasks@0.5.15-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-adr-backend@0.4.7-next.1 + - @backstage/plugin-app-backend@0.3.58-next.1 + - @backstage/plugin-auth-node@0.4.4-next.1 + - @backstage/plugin-badges-backend@0.3.7-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.1 + - @backstage/plugin-catalog-node@1.6.2-next.1 + - @backstage/plugin-code-coverage-backend@0.2.24-next.1 + - @backstage/plugin-devtools-backend@0.2.7-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.7-next.1 + - @backstage/plugin-events-backend@0.2.19-next.1 + - @backstage/plugin-events-node@0.2.19-next.1 + - @backstage/plugin-explore-backend@0.0.20-next.1 + - @backstage/plugin-jenkins-backend@0.3.4-next.1 + - @backstage/plugin-kafka-backend@0.3.8-next.1 + - @backstage/plugin-kubernetes-backend@0.14.2-next.1 + - @backstage/plugin-lighthouse-backend@0.4.2-next.1 + - @backstage/plugin-linguist-backend@0.5.7-next.1 + - @backstage/plugin-nomad-backend@0.1.12-next.1 + - @backstage/plugin-permission-backend@0.5.33-next.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.21-next.1 + - @backstage/plugin-playlist-backend@0.3.14-next.1 + - @backstage/plugin-proxy-backend@0.4.8-next.1 + - @backstage/plugin-rollbar-backend@0.1.55-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.1 + - @backstage/plugin-search-backend@1.5.0-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.14-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.14-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.19-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.1 + - @backstage/plugin-search-backend-node@1.2.14-next.1 + - @backstage/plugin-search-common@1.2.10 + - @backstage/plugin-signals-backend@0.0.1-next.1 + - @backstage/plugin-signals-node@0.0.1-next.1 + - @backstage/plugin-tech-insights-backend@0.5.24-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.1 + - @backstage/plugin-tech-insights-node@0.4.16-next.1 + - @backstage/plugin-techdocs-backend@1.9.3-next.1 + - @backstage/plugin-todo-backend@0.3.8-next.1 + +## 0.2.92-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.0 + - @backstage/plugin-azure-devops-backend@0.5.2-next.0 + - @backstage/plugin-explore-backend@0.0.20-next.0 + - @backstage/plugin-auth-backend@0.20.4-next.0 + - @backstage/backend-common@0.21.0-next.0 + - @backstage/plugin-kubernetes-backend@0.14.2-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.0 + - @backstage/plugin-catalog-backend@1.17.0-next.0 + - @backstage/plugin-search-backend@1.5.0-next.0 + - @backstage/plugin-todo-backend@0.3.8-next.0 + - @backstage/catalog-client@1.6.0-next.0 + - @backstage/plugin-signals-backend@0.0.1-next.0 + - @backstage/plugin-signals-node@0.0.1-next.0 + - @backstage/plugin-scaffolder-backend@1.21.0-next.0 + - @backstage/plugin-app-backend@0.3.58-next.0 + - example-app@0.2.92-next.0 + - @backstage/backend-tasks@0.5.15-next.0 + - @backstage/plugin-auth-node@0.4.4-next.0 + - @backstage/plugin-badges-backend@0.3.7-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.0 + - @backstage/plugin-catalog-node@1.6.2-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.7-next.0 + - @backstage/plugin-events-backend@0.2.19-next.0 + - @backstage/plugin-linguist-backend@0.5.7-next.0 + - @backstage/plugin-permission-node@0.7.21-next.0 + - @backstage/plugin-playlist-backend@0.3.14-next.0 + - @backstage/plugin-proxy-backend@0.4.8-next.0 + - @backstage/plugin-rollbar-backend@0.1.55-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.14-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.14-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.19-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.0 + - @backstage/plugin-tech-insights-backend@0.5.24-next.0 + - @backstage/plugin-techdocs-backend@1.9.3-next.0 + - @backstage/plugin-adr-backend@0.4.7-next.0 + - @backstage/plugin-azure-sites-backend@0.1.20-next.0 + - @backstage/plugin-code-coverage-backend@0.2.24-next.0 + - @backstage/plugin-devtools-backend@0.2.7-next.0 + - @backstage/plugin-jenkins-backend@0.3.4-next.0 + - @backstage/plugin-kafka-backend@0.3.8-next.0 + - @backstage/plugin-lighthouse-backend@0.4.2-next.0 + - @backstage/plugin-nomad-backend@0.1.12-next.0 + - @backstage/plugin-permission-backend@0.5.33-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.0 + - @backstage/plugin-search-backend-node@1.2.14-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.0 + - @backstage/plugin-tech-insights-node@0.4.16-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.0 + - @backstage/plugin-events-node@0.2.19-next.0 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-common@1.2.10 + +## 0.2.91 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.3 + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-backend@1.20.0 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10 + - @backstage/plugin-events-backend@0.2.18 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/plugin-azure-devops-backend@0.5.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41 + - @backstage/plugin-entity-feedback-backend@0.2.6 + - @backstage/plugin-code-coverage-backend@0.2.23 + - @backstage/plugin-azure-sites-backend@0.1.19 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/plugin-devtools-backend@0.2.6 + - @backstage/plugin-linguist-backend@0.5.6 + - @backstage/plugin-playlist-backend@0.3.13 + - @backstage/plugin-techdocs-backend@1.9.2 + - @backstage/plugin-explore-backend@0.0.19 + - @backstage/plugin-jenkins-backend@0.3.3 + - @backstage/plugin-badges-backend@0.3.6 + - @backstage/plugin-search-backend@1.4.9 + - @backstage/plugin-kafka-backend@0.3.7 + - @backstage/plugin-nomad-backend@0.1.11 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-todo-backend@0.3.7 + - @backstage/plugin-adr-backend@0.4.6 + - @backstage/plugin-app-backend@0.3.57 + - @backstage/plugin-permission-backend@0.5.32 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-catalog-backend@1.16.1 + - example-app@0.2.91 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-kubernetes-backend@0.14.1 + - @backstage/plugin-lighthouse-backend@0.4.1 + - @backstage/plugin-proxy-backend@0.4.7 + - @backstage/plugin-rollbar-backend@0.1.54 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.26 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.12 + - @backstage/plugin-search-backend-module-pg@0.5.18 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-tech-insights-backend@0.5.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 + - @backstage/plugin-events-node@0.2.18 + - @backstage/plugin-search-common@1.2.10 + +## 0.2.91-next.2 + +### Patch Changes + +- Updated dependencies + - example-app@0.2.91-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-adr-backend@0.4.6-next.2 + - @backstage/plugin-app-backend@0.3.57-next.2 + - @backstage/plugin-auth-backend@0.20.3-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-azure-devops-backend@0.5.1-next.2 + - @backstage/plugin-badges-backend@0.3.6-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-code-coverage-backend@0.2.23-next.2 + - @backstage/plugin-devtools-backend@0.2.6-next.2 + - @backstage/plugin-entity-feedback-backend@0.2.6-next.2 + - @backstage/plugin-events-backend@0.2.18-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/plugin-jenkins-backend@0.3.3-next.2 + - @backstage/plugin-kafka-backend@0.3.7-next.2 + - @backstage/plugin-kubernetes-backend@0.14.1-next.2 + - @backstage/plugin-lighthouse-backend@0.4.1-next.2 + - @backstage/plugin-linguist-backend@0.5.6-next.2 + - @backstage/plugin-nomad-backend@0.1.11-next.2 + - @backstage/plugin-permission-backend@0.5.32-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-playlist-backend@0.3.13-next.2 + - @backstage/plugin-proxy-backend@0.4.7-next.2 + - @backstage/plugin-scaffolder-backend@1.19.3-next.2 + - @backstage/plugin-search-backend@1.4.9-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.18-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + - @backstage/plugin-techdocs-backend@1.9.2-next.2 + - @backstage/plugin-todo-backend@0.3.7-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/plugin-azure-sites-backend@0.1.19-next.2 + - @backstage/plugin-explore-backend@0.0.19-next.2 + - @backstage/plugin-rollbar-backend@0.1.54-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.2 + - @backstage/plugin-tech-insights-backend@0.5.23-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.2 + - @backstage/plugin-tech-insights-node@0.4.15-next.2 + +## 0.2.91-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.1 + - example-app@0.2.91-next.1 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-app-backend@0.3.57-next.1 + - @backstage/plugin-devtools-backend@0.2.6-next.1 + - @backstage/plugin-proxy-backend@0.4.7-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-kubernetes-backend@0.14.1-next.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-adr-backend@0.4.6-next.1 + - @backstage/plugin-auth-backend@0.20.3-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-azure-devops-backend@0.5.1-next.1 + - @backstage/plugin-azure-sites-backend@0.1.19-next.1 + - @backstage/plugin-badges-backend@0.3.6-next.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/plugin-code-coverage-backend@0.2.23-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.6-next.1 + - @backstage/plugin-events-backend@0.2.18-next.1 + - @backstage/plugin-explore-backend@0.0.19-next.1 + - @backstage/plugin-jenkins-backend@0.3.3-next.1 + - @backstage/plugin-kafka-backend@0.3.7-next.1 + - @backstage/plugin-lighthouse-backend@0.4.1-next.1 + - @backstage/plugin-linguist-backend@0.5.6-next.1 + - @backstage/plugin-nomad-backend@0.1.11-next.1 + - @backstage/plugin-permission-backend@0.5.32-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-playlist-backend@0.3.13-next.1 + - @backstage/plugin-rollbar-backend@0.1.54-next.1 + - @backstage/plugin-scaffolder-backend@1.19.3-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.1 + - @backstage/plugin-search-backend@1.4.9-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.18-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/plugin-tech-insights-backend@0.5.23-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.1 + - @backstage/plugin-tech-insights-node@0.4.15-next.1 + - @backstage/plugin-techdocs-backend@1.9.2-next.1 + - @backstage/plugin-todo-backend@0.3.7-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-common@1.2.9 + +## 0.2.91-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.3-next.0 + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-scaffolder-backend@1.19.3-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.0 + - @backstage/plugin-azure-devops-backend@0.5.1-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.6-next.0 + - @backstage/plugin-code-coverage-backend@0.2.23-next.0 + - @backstage/plugin-azure-sites-backend@0.1.19-next.0 + - @backstage/plugin-tech-insights-node@0.4.15-next.0 + - @backstage/plugin-devtools-backend@0.2.6-next.0 + - @backstage/plugin-linguist-backend@0.5.6-next.0 + - @backstage/plugin-playlist-backend@0.3.13-next.0 + - @backstage/plugin-techdocs-backend@1.9.2-next.0 + - @backstage/plugin-explore-backend@0.0.19-next.0 + - @backstage/plugin-jenkins-backend@0.3.3-next.0 + - @backstage/plugin-badges-backend@0.3.6-next.0 + - @backstage/plugin-search-backend@1.4.9-next.0 + - @backstage/plugin-kafka-backend@0.3.7-next.0 + - @backstage/plugin-nomad-backend@0.1.11-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/plugin-todo-backend@0.3.7-next.0 + - @backstage/plugin-adr-backend@0.4.6-next.0 + - @backstage/plugin-app-backend@0.3.57-next.0 + - example-app@0.2.91-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.0 + - @backstage/plugin-events-backend@0.2.18-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + - @backstage/plugin-kubernetes-backend@0.14.1-next.0 + - @backstage/plugin-lighthouse-backend@0.4.1-next.0 + - @backstage/plugin-permission-backend@0.5.32-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-proxy-backend@0.4.7-next.0 + - @backstage/plugin-rollbar-backend@0.1.54-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.18-next.0 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + - @backstage/plugin-tech-insights-backend@0.5.23-next.0 + +## 0.2.90 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.1 + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-techdocs-backend@1.9.1 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-azure-devops-backend@0.5.0 + - @backstage/plugin-scaffolder-backend@1.19.2 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-lighthouse-backend@0.4.0 + - @backstage/plugin-kubernetes-backend@0.14.0 + - @backstage/integration@1.8.0 + - @backstage/plugin-azure-sites-backend@0.1.18 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-backend@0.5.31 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-playlist-backend@0.3.12 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/plugin-search-backend@1.4.8 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5 + - @backstage/plugin-search-backend-module-techdocs@0.1.12 + - @backstage/plugin-search-backend-module-catalog@0.1.12 + - @backstage/plugin-search-backend-module-explore@0.1.12 + - @backstage/plugin-search-backend-module-pg@0.5.17 + - @backstage/plugin-events-backend@0.2.17 + - example-app@0.2.90 + - @backstage/plugin-adr-backend@0.4.5 + - @backstage/plugin-app-backend@0.3.56 + - @backstage/plugin-badges-backend@0.3.5 + - @backstage/plugin-code-coverage-backend@0.2.22 + - @backstage/plugin-devtools-backend@0.2.5 + - @backstage/plugin-entity-feedback-backend@0.2.5 + - @backstage/plugin-explore-backend@0.0.18 + - @backstage/plugin-jenkins-backend@0.3.2 + - @backstage/plugin-kafka-backend@0.3.6 + - @backstage/plugin-linguist-backend@0.5.5 + - @backstage/plugin-nomad-backend@0.1.10 + - @backstage/plugin-proxy-backend@0.4.6 + - @backstage/plugin-rollbar-backend@0.1.53 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/plugin-tech-insights-backend@0.5.22 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40 + - @backstage/plugin-tech-insights-node@0.4.14 + - @backstage/plugin-todo-backend@0.3.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17 + - @backstage/plugin-search-common@1.2.9 + +## 0.2.90-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-azure-devops-backend@0.5.0-next.3 + - @backstage/plugin-scaffolder-backend@1.19.2-next.3 + - @backstage/backend-common@0.20.0-next.3 + - example-app@0.2.90-next.4 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-adr-backend@0.4.5-next.3 + - @backstage/plugin-app-backend@0.3.56-next.3 + - @backstage/plugin-auth-backend@0.20.1-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-azure-sites-backend@0.1.18-next.3 + - @backstage/plugin-badges-backend@0.3.5-next.3 + - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.3 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-code-coverage-backend@0.2.22-next.3 + - @backstage/plugin-devtools-backend@0.2.5-next.3 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.3 + - @backstage/plugin-events-backend@0.2.17-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + - @backstage/plugin-explore-backend@0.0.18-next.3 + - @backstage/plugin-jenkins-backend@0.3.2-next.3 + - @backstage/plugin-kafka-backend@0.3.6-next.3 + - @backstage/plugin-kubernetes-backend@0.14.0-next.3 + - @backstage/plugin-lighthouse-backend@0.4.0-next.3 + - @backstage/plugin-linguist-backend@0.5.5-next.3 + - @backstage/plugin-nomad-backend@0.1.10-next.3 + - @backstage/plugin-permission-backend@0.5.31-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-playlist-backend@0.3.12-next.3 + - @backstage/plugin-proxy-backend@0.4.6-next.3 + - @backstage/plugin-rollbar-backend@0.1.53-next.3 + - @backstage/plugin-search-backend@1.4.8-next.3 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.3 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.3 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.3 + - @backstage/plugin-search-backend-module-pg@0.5.17-next.3 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.3 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-tech-insights-backend@0.5.22-next.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.3 + - @backstage/plugin-tech-insights-node@0.4.14-next.3 + - @backstage/plugin-techdocs-backend@1.9.1-next.3 + - @backstage/plugin-todo-backend@0.3.6-next.3 + +## 0.2.90-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/plugin-catalog-backend@1.16.0-next.2 + - @backstage/plugin-auth-backend@0.20.1-next.2 + - @backstage/plugin-lighthouse-backend@0.4.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.17-next.2 + - @backstage/plugin-events-backend@0.2.17-next.2 + - example-app@0.2.90-next.3 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-adr-backend@0.4.5-next.2 + - @backstage/plugin-app-backend@0.3.56-next.2 + - @backstage/plugin-azure-devops-backend@0.5.0-next.2 + - @backstage/plugin-azure-sites-backend@0.1.18-next.2 + - @backstage/plugin-badges-backend@0.3.5-next.2 + - @backstage/plugin-code-coverage-backend@0.2.22-next.2 + - @backstage/plugin-devtools-backend@0.2.5-next.2 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.2 + - @backstage/plugin-events-node@0.2.17-next.2 + - @backstage/plugin-explore-backend@0.0.18-next.2 + - @backstage/plugin-jenkins-backend@0.3.2-next.2 + - @backstage/plugin-kafka-backend@0.3.6-next.2 + - @backstage/plugin-kubernetes-backend@0.14.0-next.2 + - @backstage/plugin-linguist-backend@0.5.5-next.2 + - @backstage/plugin-nomad-backend@0.1.10-next.2 + - @backstage/plugin-permission-backend@0.5.31-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-playlist-backend@0.3.12-next.2 + - @backstage/plugin-proxy-backend@0.4.6-next.2 + - @backstage/plugin-rollbar-backend@0.1.53-next.2 + - @backstage/plugin-scaffolder-backend@1.19.2-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.2 + - @backstage/plugin-search-backend@1.4.8-next.2 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-tech-insights-backend@0.5.22-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.2 + - @backstage/plugin-tech-insights-node@0.4.14-next.2 + - @backstage/plugin-techdocs-backend@1.9.1-next.2 + - @backstage/plugin-todo-backend@0.3.6-next.2 + +## 0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.1-next.1 + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-azure-devops-backend@0.5.0-next.1 + - @backstage/plugin-kubernetes-backend@0.14.0-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-azure-sites-backend@0.1.18-next.1 + - @backstage/backend-common@0.20.0-next.1 + - example-app@0.2.90-next.2 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-adr-backend@0.4.5-next.1 + - @backstage/plugin-app-backend@0.3.56-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-code-coverage-backend@0.2.22-next.1 + - @backstage/plugin-devtools-backend@0.2.5-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-explore-backend@0.0.18-next.1 + - @backstage/plugin-jenkins-backend@0.3.2-next.1 + - @backstage/plugin-kafka-backend@0.3.6-next.1 + - @backstage/plugin-lighthouse-backend@0.3.5-next.1 + - @backstage/plugin-linguist-backend@0.5.5-next.1 + - @backstage/plugin-nomad-backend@0.1.10-next.1 + - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-backend@0.3.12-next.1 + - @backstage/plugin-proxy-backend@0.4.6-next.1 + - @backstage/plugin-rollbar-backend@0.1.53-next.1 + - @backstage/plugin-scaffolder-backend@1.19.2-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.1 + - @backstage/plugin-search-backend@1.4.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.17-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-tech-insights-backend@0.5.22-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.1 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + - @backstage/plugin-techdocs-backend@1.9.1-next.1 + - @backstage/plugin-todo-backend@0.3.6-next.1 + +## 0.2.90-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-backend@0.20.1-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-scaffolder-backend@1.19.2-next.0 + - @backstage/plugin-kubernetes-backend@0.14.0-next.0 + - @backstage/plugin-azure-sites-backend@0.1.18-next.0 + - @backstage/integration@1.8.0-next.0 + - example-app@0.2.90-next.0 + - @backstage/plugin-adr-backend@0.4.5-next.0 + - @backstage/plugin-app-backend@0.3.56-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-azure-devops-backend@0.4.5-next.0 + - @backstage/plugin-badges-backend@0.3.5-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-code-coverage-backend@0.2.22-next.0 + - @backstage/plugin-devtools-backend@0.2.5-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.0 + - @backstage/plugin-events-backend@0.2.17-next.0 + - @backstage/plugin-explore-backend@0.0.18-next.0 + - @backstage/plugin-jenkins-backend@0.3.2-next.0 + - @backstage/plugin-kafka-backend@0.3.6-next.0 + - @backstage/plugin-lighthouse-backend@0.3.5-next.0 + - @backstage/plugin-linguist-backend@0.5.5-next.0 + - @backstage/plugin-nomad-backend@0.1.10-next.0 + - @backstage/plugin-permission-backend@0.5.31-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/plugin-playlist-backend@0.3.12-next.0 + - @backstage/plugin-proxy-backend@0.4.6-next.0 + - @backstage/plugin-rollbar-backend@0.1.53-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.0 + - @backstage/plugin-search-backend@1.4.8-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.17-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/plugin-tech-insights-backend@0.5.22-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.0 + - @backstage/plugin-tech-insights-node@0.4.14-next.0 + - @backstage/plugin-techdocs-backend@1.9.1-next.0 + - @backstage/plugin-todo-backend@0.3.6-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.0 + - @backstage/plugin-events-node@0.2.17-next.0 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## 0.2.89 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-search-backend-module-pg@0.5.16 + - @backstage/plugin-kubernetes-backend@0.13.1 + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/integration@1.7.2 + - @backstage/plugin-auth-backend@0.20.0 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-techdocs-backend@1.9.0 + - @backstage/plugin-code-coverage-backend@0.2.21 + - @backstage/plugin-scaffolder-backend@1.19.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.10 + - @backstage/plugin-search-backend@1.4.7 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4 + - @backstage/plugin-entity-feedback-backend@0.2.4 + - @backstage/plugin-tech-insights-backend@0.5.21 + - @backstage/plugin-linguist-backend@0.5.4 + - @backstage/plugin-playlist-backend@0.3.11 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-badges-backend@0.3.4 + - @backstage/plugin-app-backend@0.3.55 + - @backstage/plugin-search-backend-module-techdocs@0.1.11 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-jenkins-backend@0.3.1 + - @backstage/plugin-adr-backend@0.4.4 + - @backstage/plugin-kafka-backend@0.3.5 + - @backstage/plugin-proxy-backend@0.4.5 + - example-app@0.2.89 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4 + - @backstage/plugin-lighthouse-backend@0.3.4 + - @backstage/plugin-search-backend-module-catalog@0.1.11 + - @backstage/plugin-todo-backend@0.3.5 + - @backstage/plugin-devtools-backend@0.2.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-azure-devops-backend@0.4.4 + - @backstage/plugin-azure-sites-backend@0.1.17 + - @backstage/plugin-events-backend@0.2.16 + - @backstage/plugin-events-node@0.2.16 + - @backstage/plugin-explore-backend@0.0.17 + - @backstage/plugin-graphql-backend@0.2.1 + - @backstage/plugin-nomad-backend@0.1.9 + - @backstage/plugin-permission-backend@0.5.30 + - @backstage/plugin-permission-node@0.7.18 + - @backstage/plugin-rollbar-backend@0.1.52 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.24 + - @backstage/plugin-search-backend-module-explore@0.1.11 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39 + - @backstage/plugin-tech-insights-node@0.4.13 + +## 0.2.89-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.13.1-next.2 + - @backstage/plugin-scaffolder-backend@1.19.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.10-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.16-next.2 + - @backstage/plugin-entity-feedback-backend@0.2.4-next.2 + - @backstage/plugin-code-coverage-backend@0.2.21-next.2 + - @backstage/plugin-tech-insights-backend@0.5.21-next.2 + - @backstage/plugin-linguist-backend@0.5.4-next.2 + - @backstage/plugin-playlist-backend@0.3.11-next.2 + - @backstage/plugin-techdocs-backend@1.9.0-next.2 + - @backstage/backend-common@0.19.9-next.2 + - @backstage/plugin-catalog-backend@1.15.0-next.2 + - @backstage/backend-tasks@0.5.12-next.2 + - @backstage/plugin-badges-backend@0.3.4-next.2 + - @backstage/plugin-auth-backend@0.20.0-next.2 + - @backstage/plugin-app-backend@0.3.55-next.2 + - example-app@0.2.89-next.2 + - @backstage/plugin-adr-backend@0.4.4-next.2 + - @backstage/plugin-auth-node@0.4.1-next.2 + - @backstage/plugin-azure-devops-backend@0.4.4-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.2 + - @backstage/plugin-catalog-node@1.5.0-next.2 + - @backstage/plugin-devtools-backend@0.2.4-next.2 + - @backstage/plugin-events-backend@0.2.16-next.2 + - @backstage/plugin-events-node@0.2.16-next.2 + - @backstage/plugin-jenkins-backend@0.3.1-next.2 + - @backstage/plugin-kafka-backend@0.3.5-next.2 + - @backstage/plugin-lighthouse-backend@0.3.4-next.2 + - @backstage/plugin-nomad-backend@0.1.9-next.2 + - @backstage/plugin-permission-backend@0.5.30-next.2 + - @backstage/plugin-permission-node@0.7.18-next.2 + - @backstage/plugin-proxy-backend@0.4.5-next.2 + - @backstage/plugin-search-backend@1.4.7-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.11-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.11-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.2 + - @backstage/plugin-search-backend-node@1.2.11-next.2 + - @backstage/plugin-todo-backend@0.3.5-next.2 + - @backstage/plugin-rollbar-backend@0.1.52-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.24-next.2 + - @backstage/plugin-azure-sites-backend@0.1.17-next.2 + - @backstage/plugin-explore-backend@0.0.17-next.2 + - @backstage/plugin-graphql-backend@0.2.1-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39-next.2 + - @backstage/plugin-tech-insights-node@0.4.13-next.2 + +## 0.2.89-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0-next.1 + - @backstage/plugin-catalog-node@1.5.0-next.1 + - @backstage/integration@1.7.2-next.0 + - @backstage/plugin-auth-backend@0.20.0-next.1 + - @backstage/plugin-techdocs-backend@1.9.0-next.1 + - @backstage/plugin-scaffolder-backend@1.19.0-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.1 + - @backstage/plugin-jenkins-backend@0.3.1-next.1 + - @backstage/plugin-kubernetes-backend@0.13.1-next.1 + - @backstage/plugin-lighthouse-backend@0.3.4-next.1 + - @backstage/plugin-linguist-backend@0.5.4-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.11-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.1 + - @backstage/plugin-todo-backend@0.3.5-next.1 + - example-app@0.2.89-next.1 + - @backstage/backend-common@0.19.9-next.1 + - @backstage/plugin-adr-backend@0.4.4-next.1 + - @backstage/plugin-code-coverage-backend@0.2.21-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.24-next.1 + - @backstage/backend-tasks@0.5.12-next.1 + - @backstage/plugin-app-backend@0.3.55-next.1 + - @backstage/plugin-auth-node@0.4.1-next.1 + - @backstage/plugin-badges-backend@0.3.4-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.4-next.1 + - @backstage/plugin-events-backend@0.2.16-next.1 + - @backstage/plugin-permission-node@0.7.18-next.1 + - @backstage/plugin-playlist-backend@0.3.11-next.1 + - @backstage/plugin-proxy-backend@0.4.5-next.1 + - @backstage/plugin-rollbar-backend@0.1.52-next.1 + - @backstage/plugin-search-backend@1.4.7-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.11-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.16-next.1 + - @backstage/plugin-tech-insights-backend@0.5.21-next.1 + - @backstage/plugin-azure-devops-backend@0.4.4-next.1 + - @backstage/plugin-azure-sites-backend@0.1.17-next.1 + - @backstage/plugin-devtools-backend@0.2.4-next.1 + - @backstage/plugin-explore-backend@0.0.17-next.1 + - @backstage/plugin-graphql-backend@0.2.1-next.1 + - @backstage/plugin-kafka-backend@0.3.5-next.1 + - @backstage/plugin-nomad-backend@0.1.9-next.1 + - @backstage/plugin-permission-backend@0.5.30-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.10-next.1 + - @backstage/plugin-search-backend-node@1.2.11-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39-next.1 + - @backstage/plugin-tech-insights-node@0.4.13-next.1 + - @backstage/catalog-client@1.4.5 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.1 + - @backstage/plugin-events-node@0.2.16-next.1 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## 0.2.89-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.2.11-next.0 + - @backstage/plugin-techdocs-backend@1.8.1-next.0 + - @backstage/plugin-code-coverage-backend@0.2.21-next.0 + - @backstage/plugin-scaffolder-backend@1.19.0-next.0 + - @backstage/plugin-catalog-backend@1.15.0-next.0 + - @backstage/plugin-search-backend@1.4.7-next.0 + - @backstage/plugin-tech-insights-backend@0.5.21-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.0 + - @backstage/plugin-kafka-backend@0.3.5-next.0 + - @backstage/plugin-proxy-backend@0.4.5-next.0 + - @backstage/plugin-auth-backend@0.20.0-next.0 + - @backstage/backend-common@0.19.9-next.0 + - @backstage/integration@1.7.1 + - @backstage/plugin-app-backend@0.3.55-next.0 + - @backstage/plugin-devtools-backend@0.2.4-next.0 + - example-app@0.2.89-next.0 + - @backstage/backend-tasks@0.5.12-next.0 + - @backstage/catalog-client@1.4.5 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-adr-backend@0.4.4-next.0 + - @backstage/plugin-auth-node@0.4.1-next.0 + - @backstage/plugin-azure-devops-backend@0.4.4-next.0 + - @backstage/plugin-azure-sites-backend@0.1.17-next.0 + - @backstage/plugin-badges-backend@0.3.4-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.0 + - @backstage/plugin-catalog-node@1.4.8-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.4-next.0 + - @backstage/plugin-events-backend@0.2.16-next.0 + - @backstage/plugin-events-node@0.2.16-next.0 + - @backstage/plugin-explore-backend@0.0.17-next.0 + - @backstage/plugin-graphql-backend@0.2.1-next.0 + - @backstage/plugin-jenkins-backend@0.3.1-next.0 + - @backstage/plugin-kubernetes-backend@0.13.1-next.0 + - @backstage/plugin-lighthouse-backend@0.3.4-next.0 + - @backstage/plugin-linguist-backend@0.5.4-next.0 + - @backstage/plugin-nomad-backend@0.1.9-next.0 + - @backstage/plugin-permission-backend@0.5.30-next.0 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-permission-node@0.7.18-next.0 + - @backstage/plugin-playlist-backend@0.3.11-next.0 + - @backstage/plugin-rollbar-backend@0.1.52-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.24-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.11-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.10-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.11-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.16-next.0 + - @backstage/plugin-search-common@1.2.7 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39-next.0 + - @backstage/plugin-tech-insights-node@0.4.13-next.0 + - @backstage/plugin-todo-backend@0.3.5-next.0 + +## 0.2.88 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-nomad-backend@0.1.8 + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-scaffolder-backend@1.18.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.9 + - @backstage/integration@1.7.1 + - @backstage/plugin-playlist-backend@0.3.10 + - @backstage/plugin-techdocs-backend@1.8.0 + - @backstage/plugin-auth-backend@0.19.3 + - @backstage/plugin-rollbar-backend@0.1.51 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/plugin-graphql-backend@0.2.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-badges-backend@0.3.3 + - @backstage/plugin-tech-insights-backend@0.5.20 + - @backstage/plugin-kubernetes-backend@0.13.0 + - @backstage/plugin-jenkins-backend@0.3.0 + - @backstage/plugin-code-coverage-backend@0.2.20 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.23 + - @backstage/plugin-search-backend@1.4.6 + - example-app@0.2.88 + - @backstage/plugin-lighthouse-backend@0.3.3 + - @backstage/plugin-linguist-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.10 + - @backstage/plugin-search-backend-module-explore@0.1.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.10 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/plugin-adr-backend@0.4.3 + - @backstage/plugin-app-backend@0.3.54 + - @backstage/plugin-azure-devops-backend@0.4.3 + - @backstage/plugin-azure-sites-backend@0.1.16 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + - @backstage/plugin-devtools-backend@0.2.3 + - @backstage/plugin-entity-feedback-backend@0.2.3 + - @backstage/plugin-events-backend@0.2.15 + - @backstage/plugin-explore-backend@0.0.16 + - @backstage/plugin-kafka-backend@0.3.3 + - @backstage/plugin-permission-backend@0.5.29 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-proxy-backend@0.4.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.7 + - @backstage/plugin-search-backend-module-pg@0.5.15 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.38 + - @backstage/plugin-todo-backend@0.3.4 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## 0.2.88-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-nomad-backend@0.1.8-next.2 + - @backstage/backend-common@0.19.8-next.2 + - @backstage/plugin-scaffolder-backend@1.18.0-next.2 + - @backstage/plugin-techdocs-backend@1.8.0-next.2 + - @backstage/plugin-auth-node@0.4.0-next.2 + - @backstage/plugin-catalog-backend@1.14.0-next.2 + - @backstage/catalog-model@1.4.3-next.0 + - @backstage/integration@1.7.1-next.1 + - @backstage/plugin-kubernetes-backend@0.12.3-next.2 + - @backstage/plugin-jenkins-backend@0.2.9-next.2 + - @backstage/plugin-auth-backend@0.19.3-next.2 + - @backstage/backend-tasks@0.5.11-next.2 + - @backstage/plugin-adr-backend@0.4.3-next.2 + - @backstage/plugin-app-backend@0.3.54-next.2 + - @backstage/plugin-azure-devops-backend@0.4.3-next.2 + - @backstage/plugin-azure-sites-backend@0.1.16-next.2 + - @backstage/plugin-badges-backend@0.3.3-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3-next.2 + - @backstage/plugin-catalog-node@1.4.7-next.2 + - @backstage/plugin-code-coverage-backend@0.2.20-next.2 + - @backstage/plugin-devtools-backend@0.2.3-next.2 + - @backstage/plugin-entity-feedback-backend@0.2.3-next.2 + - @backstage/plugin-events-backend@0.2.15-next.2 + - @backstage/plugin-explore-backend@0.0.16-next.2 + - @backstage/plugin-graphql-backend@0.1.44-next.2 + - @backstage/plugin-kafka-backend@0.3.3-next.2 + - @backstage/plugin-lighthouse-backend@0.3.3-next.2 + - @backstage/plugin-linguist-backend@0.5.3-next.2 + - @backstage/plugin-permission-backend@0.5.29-next.2 + - @backstage/plugin-permission-node@0.7.17-next.2 + - @backstage/plugin-playlist-backend@0.3.10-next.2 + - @backstage/plugin-proxy-backend@0.4.3-next.2 + - @backstage/plugin-rollbar-backend@0.1.51-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.7-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.23-next.2 + - @backstage/plugin-search-backend@1.4.6-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.10-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.9-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.10-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.15-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.10-next.2 + - @backstage/plugin-search-backend-node@1.2.10-next.2 + - @backstage/plugin-tech-insights-backend@0.5.20-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.38-next.2 + - @backstage/plugin-tech-insights-node@0.4.12-next.2 + - @backstage/plugin-todo-backend@0.3.4-next.2 + - example-app@0.2.88-next.2 + - @backstage/catalog-client@1.4.5-next.0 + - @backstage/config@1.1.1-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3-next.2 + - @backstage/plugin-events-node@0.2.15-next.2 + - @backstage/plugin-permission-common@0.7.9-next.0 + - @backstage/plugin-search-common@1.2.7-next.0 + +## 0.2.88-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-backend@1.18.0-next.1 + - @backstage/plugin-badges-backend@0.3.2-next.1 + - @backstage/plugin-lighthouse-backend@0.3.2-next.1 + - @backstage/plugin-linguist-backend@0.5.2-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-tech-insights-backend@0.5.19-next.1 + - @backstage/plugin-tech-insights-node@0.4.11-next.1 + - example-app@0.2.88-next.1 + - @backstage/plugin-auth-backend@0.19.2-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + - @backstage/plugin-kubernetes-backend@0.12.2-next.1 + - @backstage/plugin-todo-backend@0.3.3-next.1 + - @backstage/plugin-adr-backend@0.4.2-next.1 + - @backstage/plugin-app-backend@0.3.53-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-azure-devops-backend@0.4.2-next.1 + - @backstage/plugin-azure-sites-backend@0.1.15-next.1 + - @backstage/plugin-code-coverage-backend@0.2.19-next.1 + - @backstage/plugin-devtools-backend@0.2.2-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.1 + - @backstage/plugin-events-backend@0.2.14-next.1 + - @backstage/plugin-explore-backend@0.0.15-next.1 + - @backstage/plugin-graphql-backend@0.1.43-next.1 + - @backstage/plugin-jenkins-backend@0.2.8-next.1 + - @backstage/plugin-kafka-backend@0.3.2-next.1 + - @backstage/plugin-nomad-backend@0.1.7-next.1 + - @backstage/plugin-permission-backend@0.5.28-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-playlist-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.4.2-next.1 + - @backstage/plugin-rollbar-backend@0.1.50-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.1 + - @backstage/plugin-search-backend@1.4.5-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.14-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.1 + - @backstage/plugin-techdocs-backend@1.7.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 0.2.88-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-playlist-backend@0.3.9-next.0 + - @backstage/plugin-rollbar-backend@0.1.50-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-tech-insights-backend@0.5.19-next.0 + - @backstage/plugin-code-coverage-backend@0.2.19-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.0 + - @backstage/backend-common@0.19.7-next.0 + - example-app@0.2.88-next.0 + - @backstage/plugin-adr-backend@0.4.2-next.0 + - @backstage/plugin-scaffolder-backend@1.17.3-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.0 + - @backstage/plugin-techdocs-backend@1.7.2-next.0 + - @backstage/plugin-todo-backend@0.3.3-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-app-backend@0.3.53-next.0 + - @backstage/plugin-auth-backend@0.19.2-next.0 + - @backstage/plugin-azure-devops-backend@0.4.2-next.0 + - @backstage/plugin-azure-sites-backend@0.1.15-next.0 + - @backstage/plugin-badges-backend@0.3.2-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-devtools-backend@0.2.2-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.0 + - @backstage/plugin-events-backend@0.2.14-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-explore-backend@0.0.15-next.0 + - @backstage/plugin-graphql-backend@0.1.43-next.0 + - @backstage/plugin-jenkins-backend@0.2.8-next.0 + - @backstage/plugin-kafka-backend@0.3.2-next.0 + - @backstage/plugin-kubernetes-backend@0.12.2-next.0 + - @backstage/plugin-lighthouse-backend@0.3.2-next.0 + - @backstage/plugin-linguist-backend@0.5.2-next.0 + - @backstage/plugin-nomad-backend@0.1.7-next.0 + - @backstage/plugin-permission-backend@0.5.28-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-proxy-backend@0.4.2-next.0 + - @backstage/plugin-search-backend@1.4.5-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.14-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.0 + - @backstage/plugin-tech-insights-node@0.4.11-next.0 + +## 0.2.87 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-pg@0.5.12 + - @backstage/plugin-catalog-backend@1.13.0 + - @backstage/plugin-kubernetes-backend@0.12.0 + - @backstage/plugin-techdocs-backend@1.7.0 + - @backstage/plugin-auth-backend@0.19.0 + - @backstage/plugin-proxy-backend@0.4.0 + - @backstage/plugin-adr-backend@0.4.0 + - @backstage/plugin-azure-devops-backend@0.4.0 + - @backstage/plugin-badges-backend@0.3.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.0 + - @backstage/plugin-devtools-backend@0.2.0 + - @backstage/plugin-entity-feedback-backend@0.2.0 + - @backstage/plugin-kafka-backend@0.3.0 + - @backstage/plugin-lighthouse-backend@0.3.0 + - @backstage/plugin-linguist-backend@0.5.0 + - @backstage/plugin-todo-backend@0.3.0 + - @backstage/plugin-app-backend@0.3.51 + - @backstage/plugin-events-backend@0.2.12 + - @backstage/plugin-permission-backend@0.5.26 + - @backstage/plugin-scaffolder-backend@1.17.0 + - @backstage/plugin-search-backend@1.4.3 + - @backstage/plugin-search-backend-module-catalog@0.1.7 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.6 + - @backstage/plugin-search-backend-module-explore@0.1.7 + - @backstage/plugin-search-backend-module-techdocs@0.1.7 + - @backstage/plugin-code-coverage-backend@0.2.17 + - @backstage/backend-tasks@0.5.8 + - @backstage/backend-common@0.19.5 + - @backstage/plugin-auth-node@0.3.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + - @backstage/plugin-permission-node@0.7.14 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0 + - @backstage/plugin-tech-insights-backend@0.5.17 + - example-app@0.2.87 + - @backstage/plugin-catalog-node@1.4.4 + - @backstage/plugin-playlist-backend@0.3.7 + - @backstage/plugin-rollbar-backend@0.1.48 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4 + - @backstage/plugin-azure-sites-backend@0.1.13 + - @backstage/plugin-events-node@0.2.12 + - @backstage/plugin-explore-backend@0.0.13 + - @backstage/plugin-graphql-backend@0.1.41 + - @backstage/plugin-jenkins-backend@0.2.6 + - @backstage/plugin-nomad-backend@0.1.5 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.20 + - @backstage/plugin-search-backend-node@1.2.7 + - @backstage/plugin-tech-insights-node@0.4.9 + +## 0.2.87-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.7.0-next.3 + - @backstage/plugin-proxy-backend@0.4.0-next.3 + - @backstage/plugin-adr-backend@0.4.0-next.3 + - @backstage/plugin-auth-backend@0.19.0-next.3 + - @backstage/plugin-azure-devops-backend@0.4.0-next.3 + - @backstage/plugin-badges-backend@0.3.0-next.3 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.0-next.3 + - @backstage/plugin-devtools-backend@0.2.0-next.3 + - @backstage/plugin-entity-feedback-backend@0.2.0-next.3 + - @backstage/plugin-kafka-backend@0.3.0-next.3 + - @backstage/plugin-lighthouse-backend@0.3.0-next.3 + - @backstage/plugin-linguist-backend@0.5.0-next.3 + - @backstage/plugin-todo-backend@0.3.0-next.3 + - @backstage/plugin-app-backend@0.3.51-next.3 + - @backstage/plugin-catalog-backend@1.13.0-next.3 + - @backstage/plugin-events-backend@0.2.12-next.3 + - @backstage/plugin-kubernetes-backend@0.11.6-next.3 + - @backstage/plugin-permission-backend@0.5.26-next.3 + - @backstage/plugin-scaffolder-backend@1.17.0-next.3 + - @backstage/plugin-search-backend@1.4.3-next.3 + - @backstage/plugin-search-backend-module-catalog@0.1.7-next.3 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.6-next.3 + - @backstage/plugin-search-backend-module-explore@0.1.7-next.3 + - @backstage/plugin-search-backend-module-pg@0.5.12-next.3 + - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.3 + - @backstage/catalog-client@1.4.4-next.2 + - @backstage/catalog-model@1.4.2-next.2 + - @backstage/config@1.1.0-next.2 + - @backstage/integration@1.7.0-next.3 + - @backstage/plugin-permission-common@0.7.8-next.2 + - @backstage/plugin-search-common@1.2.6-next.2 + - @backstage/plugin-permission-node@0.7.14-next.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0-next.0 + - example-app@0.2.87-next.3 + - @backstage/backend-common@0.19.5-next.3 + - @backstage/plugin-explore-backend@0.0.13-next.3 + - @backstage/backend-tasks@0.5.8-next.3 + - @backstage/plugin-auth-node@0.3.0-next.3 + - @backstage/plugin-azure-sites-backend@0.1.13-next.3 + - @backstage/plugin-catalog-node@1.4.4-next.3 + - @backstage/plugin-code-coverage-backend@0.2.17-next.3 + - @backstage/plugin-events-node@0.2.12-next.3 + - @backstage/plugin-graphql-backend@0.1.41-next.3 + - @backstage/plugin-jenkins-backend@0.2.6-next.3 + - @backstage/plugin-nomad-backend@0.1.5-next.3 + - @backstage/plugin-playlist-backend@0.3.7-next.3 + - @backstage/plugin-rollbar-backend@0.1.48-next.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4-next.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.20-next.3 + - @backstage/plugin-search-backend-node@1.2.7-next.3 + - @backstage/plugin-tech-insights-backend@0.5.17-next.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35-next.3 + - @backstage/plugin-tech-insights-node@0.4.9-next.3 + +## 0.2.87-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.16.6-next.2 + - @backstage/plugin-code-coverage-backend@0.2.17-next.2 + - @backstage/plugin-permission-backend@0.5.26-next.2 + - @backstage/plugin-catalog-backend@1.13.0-next.2 + - @backstage/plugin-badges-backend@0.2.6-next.2 + - @backstage/config@1.1.0-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35-next.2 + - @backstage/plugin-tech-insights-backend@0.5.17-next.2 + - @backstage/backend-tasks@0.5.8-next.2 + - example-app@0.2.87-next.2 + - @backstage/backend-common@0.19.5-next.2 + - @backstage/plugin-app-backend@0.3.51-next.2 + - @backstage/plugin-auth-backend@0.18.9-next.2 + - @backstage/plugin-auth-node@0.3.0-next.2 + - @backstage/plugin-catalog-node@1.4.4-next.2 + - @backstage/plugin-entity-feedback-backend@0.1.9-next.2 + - @backstage/plugin-events-backend@0.2.12-next.2 + - @backstage/plugin-kubernetes-backend@0.11.6-next.2 + - @backstage/plugin-linguist-backend@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.14-next.2 + - @backstage/plugin-playlist-backend@0.3.7-next.2 + - @backstage/plugin-proxy-backend@0.3.3-next.2 + - @backstage/plugin-rollbar-backend@0.1.48-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4-next.2 + - @backstage/plugin-search-backend@1.4.3-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.7-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.7-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.12-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.2 + - @backstage/plugin-techdocs-backend@1.7.0-next.2 + - @backstage/integration@1.7.0-next.2 + - @backstage/plugin-devtools-backend@0.1.6-next.2 + - @backstage/catalog-model@1.4.2-next.1 + - @backstage/plugin-adr-backend@0.3.9-next.2 + - @backstage/plugin-azure-devops-backend@0.3.30-next.2 + - @backstage/plugin-azure-sites-backend@0.1.13-next.2 + - @backstage/plugin-explore-backend@0.0.13-next.2 + - @backstage/plugin-graphql-backend@0.1.41-next.2 + - @backstage/plugin-jenkins-backend@0.2.6-next.2 + - @backstage/plugin-kafka-backend@0.2.44-next.2 + - @backstage/plugin-lighthouse-backend@0.2.7-next.2 + - @backstage/plugin-nomad-backend@0.1.5-next.2 + - @backstage/plugin-permission-common@0.7.8-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.20-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.6-next.2 + - @backstage/plugin-search-backend-node@1.2.7-next.2 + - @backstage/plugin-tech-insights-node@0.4.9-next.2 + - @backstage/plugin-todo-backend@0.2.3-next.2 + - @backstage/catalog-client@1.4.4-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.2.3-next.2 + - @backstage/plugin-events-node@0.2.12-next.2 + - @backstage/plugin-search-common@1.2.6-next.1 + +## 0.2.87-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-pg@0.5.12-next.1 + - @backstage/plugin-kubernetes-backend@0.11.6-next.1 + - @backstage/plugin-catalog-backend@1.13.0-next.1 + - @backstage/plugin-auth-backend@0.18.9-next.1 + - @backstage/config@1.1.0-next.0 + - @backstage/integration@1.7.0-next.1 + - @backstage/plugin-devtools-backend@0.1.6-next.1 + - @backstage/backend-tasks@0.5.8-next.1 + - @backstage/plugin-techdocs-backend@1.7.0-next.1 + - @backstage/plugin-scaffolder-backend@1.16.6-next.1 + - @backstage/plugin-code-coverage-backend@0.2.17-next.1 + - example-app@0.2.87-next.1 + - @backstage/backend-common@0.19.5-next.1 + - @backstage/catalog-model@1.4.2-next.0 + - @backstage/plugin-adr-backend@0.3.9-next.1 + - @backstage/plugin-app-backend@0.3.51-next.1 + - @backstage/plugin-auth-node@0.3.0-next.1 + - @backstage/plugin-azure-devops-backend@0.3.30-next.1 + - @backstage/plugin-azure-sites-backend@0.1.13-next.1 + - @backstage/plugin-badges-backend@0.2.6-next.1 + - @backstage/plugin-entity-feedback-backend@0.1.9-next.1 + - @backstage/plugin-events-backend@0.2.12-next.1 + - @backstage/plugin-explore-backend@0.0.13-next.1 + - @backstage/plugin-graphql-backend@0.1.41-next.1 + - @backstage/plugin-jenkins-backend@0.2.6-next.1 + - @backstage/plugin-kafka-backend@0.2.44-next.1 + - @backstage/plugin-lighthouse-backend@0.2.7-next.1 + - @backstage/plugin-linguist-backend@0.4.3-next.1 + - @backstage/plugin-nomad-backend@0.1.5-next.1 + - @backstage/plugin-permission-backend@0.5.26-next.1 + - @backstage/plugin-permission-common@0.7.8-next.0 + - @backstage/plugin-permission-node@0.7.14-next.1 + - @backstage/plugin-playlist-backend@0.3.7-next.1 + - @backstage/plugin-proxy-backend@0.3.3-next.1 + - @backstage/plugin-rollbar-backend@0.1.48-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.20-next.1 + - @backstage/plugin-search-backend@1.4.3-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.7-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.6-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.7-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.1 + - @backstage/plugin-search-backend-node@1.2.7-next.1 + - @backstage/plugin-tech-insights-backend@0.5.17-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35-next.1 + - @backstage/plugin-tech-insights-node@0.4.9-next.1 + - @backstage/plugin-todo-backend@0.2.3-next.1 + - @backstage/plugin-catalog-node@1.4.4-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.2.3-next.1 + - @backstage/plugin-events-node@0.2.12-next.1 + - @backstage/catalog-client@1.4.4-next.0 + - @backstage/plugin-search-common@1.2.6-next.0 + +## 0.2.87-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.12.2-next.0 + - @backstage/plugin-auth-backend@0.18.8-next.0 + - @backstage/plugin-code-coverage-backend@0.2.16-next.0 + - @backstage/plugin-scaffolder-backend@1.16.3-next.0 + - @backstage/plugin-auth-node@0.3.0-next.0 + - @backstage/backend-common@0.19.4-next.0 + - @backstage/plugin-linguist-backend@0.4.2-next.0 + - @backstage/integration@1.7.0-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.8-next.0 + - @backstage/plugin-tech-insights-backend@0.5.16-next.0 + - @backstage/backend-tasks@0.5.7-next.0 + - @backstage/plugin-app-backend@0.3.50-next.0 + - example-app@0.2.87-next.0 + - @backstage/catalog-client@1.4.3 + - @backstage/catalog-model@1.4.1 + - @backstage/config@1.0.8 + - @backstage/plugin-adr-backend@0.3.8-next.0 + - @backstage/plugin-azure-devops-backend@0.3.29-next.0 + - @backstage/plugin-azure-sites-backend@0.1.12-next.0 + - @backstage/plugin-badges-backend@0.2.5-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.2.2-next.0 + - @backstage/plugin-catalog-node@1.4.3-next.0 + - @backstage/plugin-devtools-backend@0.1.5-next.0 + - @backstage/plugin-events-backend@0.2.11-next.0 + - @backstage/plugin-events-node@0.2.11-next.0 + - @backstage/plugin-explore-backend@0.0.12-next.0 + - @backstage/plugin-graphql-backend@0.1.40-next.0 + - @backstage/plugin-jenkins-backend@0.2.5-next.0 + - @backstage/plugin-kafka-backend@0.2.43-next.0 + - @backstage/plugin-kubernetes-backend@0.11.5-next.0 + - @backstage/plugin-lighthouse-backend@0.2.6-next.0 + - @backstage/plugin-nomad-backend@0.1.4-next.0 + - @backstage/plugin-permission-backend@0.5.25-next.0 + - @backstage/plugin-permission-common@0.7.7 + - @backstage/plugin-permission-node@0.7.13-next.0 + - @backstage/plugin-playlist-backend@0.3.6-next.0 + - @backstage/plugin-proxy-backend@0.3.2-next.0 + - @backstage/plugin-rollbar-backend@0.1.47-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.19-next.0 + - @backstage/plugin-search-backend@1.4.2-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.5-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.11-next.0 + - @backstage/plugin-search-backend-node@1.2.6-next.0 + - @backstage/plugin-search-common@1.2.5 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.34-next.0 + - @backstage/plugin-tech-insights-node@0.4.8-next.0 + - @backstage/plugin-techdocs-backend@1.6.7-next.0 + - @backstage/plugin-todo-backend@0.2.2-next.0 + +## 0.2.86 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.3.3 + - @backstage/plugin-search-backend-module-pg@0.5.9 + - @backstage/plugin-azure-devops-backend@0.3.27 + - @backstage/plugin-kubernetes-backend@0.11.3 + - @backstage/plugin-lighthouse-backend@0.2.4 + - @backstage/plugin-permission-backend@0.5.23 + - @backstage/plugin-scaffolder-backend@1.16.0 + - @backstage/plugin-devtools-backend@0.1.3 + - @backstage/plugin-techdocs-backend@1.6.5 + - @backstage/backend-common@0.19.2 + - @backstage/plugin-catalog-backend@1.12.0 + - @backstage/plugin-badges-backend@0.2.3 + - @backstage/plugin-events-backend@0.2.9 + - @backstage/plugin-search-backend@1.4.0 + - @backstage/plugin-kafka-backend@0.2.41 + - @backstage/plugin-proxy-backend@0.3.0 + - @backstage/plugin-todo-backend@0.2.0 + - @backstage/plugin-app-backend@0.3.48 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1 + - @backstage/plugin-auth-backend@0.18.6 + - @backstage/plugin-explore-backend@0.0.10 + - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.17 + - @backstage/plugin-entity-feedback-backend@0.1.6 + - @backstage/plugin-code-coverage-backend@0.2.14 + - @backstage/plugin-search-backend-node@1.2.4 + - @backstage/plugin-linguist-backend@0.4.0 + - @backstage/plugin-playlist-backend@0.3.4 + - @backstage/plugin-jenkins-backend@0.2.3 + - @backstage/plugin-nomad-backend@0.1.2 + - @backstage/plugin-catalog-node@1.4.1 + - @backstage/plugin-events-node@0.2.9 + - @backstage/plugin-auth-node@0.2.17 + - @backstage/integration@1.6.0 + - @backstage/backend-tasks@0.5.5 + - example-app@0.2.86 + - @backstage/plugin-adr-backend@0.3.6 + - @backstage/plugin-azure-sites-backend@0.1.10 + - @backstage/plugin-graphql-backend@0.1.38 + - @backstage/plugin-permission-node@0.7.11 + - @backstage/plugin-rollbar-backend@0.1.45 + - @backstage/plugin-tech-insights-backend@0.5.14 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32 + - @backstage/plugin-tech-insights-node@0.4.6 + - @backstage/catalog-client@1.4.3 + - @backstage/catalog-model@1.4.1 + - @backstage/config@1.0.8 + - @backstage/plugin-permission-common@0.7.7 + - @backstage/plugin-search-common@1.2.5 + +## 0.2.86-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.18.6-next.2 + - @backstage/plugin-scaffolder-backend@1.15.2-next.2 + - @backstage/plugin-explore-backend@0.0.10-next.2 + - @backstage/plugin-catalog-backend@1.12.0-next.2 + - @backstage/plugin-proxy-backend@0.3.0-next.2 + - @backstage/backend-tasks@0.5.5-next.2 + - @backstage/plugin-app-backend@0.3.48-next.2 + - @backstage/plugin-linguist-backend@0.4.0-next.2 + - @backstage/plugin-techdocs-backend@1.6.5-next.2 + - @backstage/backend-common@0.19.2-next.2 + - example-app@0.2.86-next.2 + - @backstage/plugin-adr-backend@0.3.6-next.2 + - @backstage/plugin-azure-devops-backend@0.3.27-next.2 + - @backstage/plugin-badges-backend@0.2.3-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.2 + - @backstage/plugin-catalog-node@1.4.1-next.2 + - @backstage/plugin-devtools-backend@0.1.3-next.2 + - @backstage/plugin-entity-feedback-backend@0.1.6-next.2 + - @backstage/plugin-events-backend@0.2.9-next.2 + - @backstage/plugin-events-node@0.2.9-next.2 + - @backstage/plugin-kafka-backend@0.2.41-next.2 + - @backstage/plugin-kubernetes-backend@0.11.3-next.2 + - @backstage/plugin-lighthouse-backend@0.2.4-next.2 + - @backstage/plugin-permission-backend@0.5.23-next.2 + - @backstage/plugin-permission-node@0.7.11-next.2 + - @backstage/plugin-search-backend@1.4.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.3-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.9-next.2 + - @backstage/plugin-search-backend-node@1.2.4-next.2 + - @backstage/plugin-todo-backend@0.2.0-next.2 + - @backstage/plugin-tech-insights-backend@0.5.14-next.2 + - @backstage/plugin-tech-insights-node@0.4.6-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.17-next.2 + - @backstage/plugin-auth-node@0.2.17-next.2 + - @backstage/plugin-azure-sites-backend@0.1.10-next.2 + - @backstage/plugin-code-coverage-backend@0.2.14-next.2 + - @backstage/plugin-graphql-backend@0.1.38-next.2 + - @backstage/plugin-jenkins-backend@0.2.3-next.2 + - @backstage/plugin-nomad-backend@0.1.2-next.2 + - @backstage/plugin-playlist-backend@0.3.4-next.2 + - @backstage/plugin-rollbar-backend@0.1.45-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32-next.2 + +## 0.2.86-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.3.3-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.9-next.1 + - @backstage/plugin-azure-devops-backend@0.3.27-next.1 + - @backstage/plugin-kubernetes-backend@0.11.3-next.1 + - @backstage/plugin-lighthouse-backend@0.2.4-next.1 + - @backstage/plugin-permission-backend@0.5.23-next.1 + - @backstage/plugin-scaffolder-backend@1.15.2-next.1 + - @backstage/plugin-devtools-backend@0.1.3-next.1 + - @backstage/plugin-techdocs-backend@1.6.5-next.1 + - @backstage/backend-common@0.19.2-next.1 + - @backstage/plugin-catalog-backend@1.12.0-next.1 + - @backstage/plugin-badges-backend@0.2.3-next.1 + - @backstage/plugin-events-backend@0.2.9-next.1 + - @backstage/plugin-search-backend@1.4.0-next.1 + - @backstage/plugin-kafka-backend@0.2.41-next.1 + - @backstage/plugin-proxy-backend@0.2.42-next.1 + - @backstage/plugin-todo-backend@0.2.0-next.1 + - @backstage/plugin-app-backend@0.3.48-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.17-next.1 + - @backstage/plugin-entity-feedback-backend@0.1.6-next.1 + - @backstage/plugin-code-coverage-backend@0.2.14-next.1 + - @backstage/plugin-search-backend-node@1.2.4-next.1 + - @backstage/plugin-linguist-backend@0.3.2-next.1 + - @backstage/plugin-playlist-backend@0.3.4-next.1 + - @backstage/plugin-explore-backend@0.0.10-next.1 + - @backstage/plugin-jenkins-backend@0.2.3-next.1 + - @backstage/plugin-nomad-backend@0.1.2-next.1 + - @backstage/plugin-catalog-node@1.4.1-next.1 + - @backstage/plugin-events-node@0.2.9-next.1 + - @backstage/plugin-auth-node@0.2.17-next.1 + - @backstage/plugin-auth-backend@0.18.6-next.1 + - @backstage/backend-tasks@0.5.5-next.1 + - @backstage/plugin-adr-backend@0.3.6-next.1 + - @backstage/plugin-azure-sites-backend@0.1.10-next.1 + - @backstage/plugin-graphql-backend@0.1.38-next.1 + - @backstage/plugin-permission-node@0.7.11-next.1 + - @backstage/plugin-rollbar-backend@0.1.45-next.1 + - @backstage/plugin-tech-insights-backend@0.5.14-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32-next.1 + - @backstage/plugin-tech-insights-node@0.4.6-next.1 + - example-app@0.2.86-next.1 + - @backstage/integration@1.5.1 + - @backstage/catalog-client@1.4.3 + - @backstage/catalog-model@1.4.1 + - @backstage/config@1.0.8 + - @backstage/plugin-permission-common@0.7.7 + - @backstage/plugin-search-common@1.2.5 + +## 0.2.86-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-linguist-backend@0.3.2-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.0 + - @backstage/plugin-search-backend-node@1.2.4-next.0 + - @backstage/plugin-todo-backend@0.2.0-next.0 + - @backstage/plugin-catalog-backend@1.12.0-next.0 + - @backstage/plugin-search-backend@1.4.0-next.0 + - example-app@0.2.86-next.0 + - @backstage/backend-common@0.19.2-next.0 + - @backstage/backend-tasks@0.5.5-next.0 + - @backstage/catalog-client@1.4.3 + - @backstage/catalog-model@1.4.1 + - @backstage/config@1.0.8 + - @backstage/integration@1.5.1 + - @backstage/plugin-adr-backend@0.3.6-next.0 + - @backstage/plugin-app-backend@0.3.48-next.0 + - @backstage/plugin-auth-backend@0.18.6-next.0 + - @backstage/plugin-auth-node@0.2.17-next.0 + - @backstage/plugin-azure-devops-backend@0.3.27-next.0 + - @backstage/plugin-azure-sites-backend@0.1.10-next.0 + - @backstage/plugin-badges-backend@0.2.3-next.0 + - @backstage/plugin-catalog-node@1.4.1-next.0 + - @backstage/plugin-code-coverage-backend@0.2.14-next.0 + - @backstage/plugin-devtools-backend@0.1.3-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.6-next.0 + - @backstage/plugin-events-backend@0.2.9-next.0 + - @backstage/plugin-events-node@0.2.9-next.0 + - @backstage/plugin-explore-backend@0.0.10-next.0 + - @backstage/plugin-graphql-backend@0.1.38-next.0 + - @backstage/plugin-jenkins-backend@0.2.3-next.0 + - @backstage/plugin-kafka-backend@0.2.41-next.0 + - @backstage/plugin-kubernetes-backend@0.11.3-next.0 + - @backstage/plugin-lighthouse-backend@0.2.4-next.0 + - @backstage/plugin-nomad-backend@0.1.2-next.0 + - @backstage/plugin-permission-backend@0.5.23-next.0 + - @backstage/plugin-permission-common@0.7.7 + - @backstage/plugin-permission-node@0.7.11-next.0 + - @backstage/plugin-playlist-backend@0.3.4-next.0 + - @backstage/plugin-proxy-backend@0.2.42-next.0 + - @backstage/plugin-rollbar-backend@0.1.45-next.0 + - @backstage/plugin-scaffolder-backend@1.15.2-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.17-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.3-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.9-next.0 + - @backstage/plugin-search-common@1.2.5 + - @backstage/plugin-tech-insights-backend@0.5.14-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32-next.0 + - @backstage/plugin-tech-insights-node@0.4.6-next.0 + - @backstage/plugin-techdocs-backend@1.6.5-next.0 + +## 0.2.85 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.11.2 + - @backstage/plugin-badges-backend@0.2.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.0 + - @backstage/plugin-devtools-backend@0.1.2 + - @backstage/plugin-tech-insights-backend@0.5.13 + - @backstage/backend-common@0.19.1 + - @backstage/plugin-scaffolder-backend@1.15.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1 + - @backstage/plugin-azure-devops-backend@0.3.26 + - @backstage/plugin-linguist-backend@0.3.1 + - @backstage/plugin-adr-backend@0.3.5 + - @backstage/plugin-lighthouse-backend@0.2.3 + - @backstage/plugin-entity-feedback-backend@0.1.5 + - @backstage/plugin-catalog-backend@1.11.0 + - @backstage/plugin-catalog-node@1.4.0 + - @backstage/plugin-auth-backend@0.18.5 + - example-app@0.2.85 + - @backstage/backend-tasks@0.5.4 + - @backstage/catalog-client@1.4.3 + - @backstage/catalog-model@1.4.1 + - @backstage/config@1.0.8 + - @backstage/integration@1.5.1 + - @backstage/plugin-app-backend@0.3.47 + - @backstage/plugin-auth-node@0.2.16 + - @backstage/plugin-azure-sites-backend@0.1.9 + - @backstage/plugin-code-coverage-backend@0.2.13 + - @backstage/plugin-events-backend@0.2.8 + - @backstage/plugin-events-node@0.2.8 + - @backstage/plugin-explore-backend@0.0.9 + - @backstage/plugin-graphql-backend@0.1.37 + - @backstage/plugin-jenkins-backend@0.2.2 + - @backstage/plugin-kafka-backend@0.2.40 + - @backstage/plugin-nomad-backend@0.1.1 + - @backstage/plugin-permission-backend@0.5.22 + - @backstage/plugin-permission-common@0.7.7 + - @backstage/plugin-permission-node@0.7.10 + - @backstage/plugin-playlist-backend@0.3.3 + - @backstage/plugin-proxy-backend@0.2.41 + - @backstage/plugin-rollbar-backend@0.1.44 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.16 + - @backstage/plugin-search-backend@1.3.3 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.2 + - @backstage/plugin-search-backend-module-pg@0.5.8 + - @backstage/plugin-search-backend-node@1.2.3 + - @backstage/plugin-search-common@1.2.5 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.31 + - @backstage/plugin-tech-insights-node@0.4.5 + - @backstage/plugin-techdocs-backend@1.6.4 + - @backstage/plugin-todo-backend@0.1.44 + +## 0.2.85-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.0-next.1 + - @backstage/plugin-devtools-backend@0.1.2-next.2 + - @backstage/plugin-tech-insights-backend@0.5.13-next.1 + - @backstage/plugin-scaffolder-backend@1.15.1-next.1 + - @backstage/plugin-kubernetes-backend@0.11.2-next.2 + - @backstage/plugin-adr-backend@0.3.5-next.1 + - example-app@0.2.85-next.2 + - @backstage/backend-common@0.19.1-next.0 + - @backstage/backend-tasks@0.5.4-next.0 + - @backstage/catalog-client@1.4.3-next.0 + - @backstage/catalog-model@1.4.1-next.0 + - @backstage/config@1.0.8 + - @backstage/integration@1.5.1-next.0 + - @backstage/plugin-app-backend@0.3.47-next.0 + - @backstage/plugin-auth-backend@0.18.5-next.1 + - @backstage/plugin-auth-node@0.2.16-next.0 + - @backstage/plugin-azure-devops-backend@0.3.26-next.1 + - @backstage/plugin-azure-sites-backend@0.1.9-next.0 + - @backstage/plugin-badges-backend@0.2.2-next.1 + - @backstage/plugin-catalog-backend@1.11.0-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1-next.0 + - @backstage/plugin-catalog-node@1.4.0-next.0 + - @backstage/plugin-code-coverage-backend@0.2.13-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.5-next.0 + - @backstage/plugin-events-backend@0.2.8-next.0 + - @backstage/plugin-events-node@0.2.8-next.0 + - @backstage/plugin-explore-backend@0.0.9-next.0 + - @backstage/plugin-graphql-backend@0.1.37-next.0 + - @backstage/plugin-jenkins-backend@0.2.2-next.0 + - @backstage/plugin-kafka-backend@0.2.40-next.0 + - @backstage/plugin-lighthouse-backend@0.2.3-next.0 + - @backstage/plugin-linguist-backend@0.3.1-next.1 + - @backstage/plugin-nomad-backend@0.1.1-next.0 + - @backstage/plugin-permission-backend@0.5.22-next.0 + - @backstage/plugin-permission-common@0.7.7-next.0 + - @backstage/plugin-permission-node@0.7.10-next.0 + - @backstage/plugin-playlist-backend@0.3.3-next.0 + - @backstage/plugin-proxy-backend@0.2.41-next.0 + - @backstage/plugin-rollbar-backend@0.1.44-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.16-next.1 + - @backstage/plugin-search-backend@1.3.3-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.2-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.8-next.0 + - @backstage/plugin-search-backend-node@1.2.3-next.0 + - @backstage/plugin-search-common@1.2.5-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.31-next.0 + - @backstage/plugin-tech-insights-node@0.4.5-next.0 + - @backstage/plugin-techdocs-backend@1.6.4-next.0 + - @backstage/plugin-todo-backend@0.1.44-next.0 + +## 0.2.85-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.11.2-next.1 + - @backstage/plugin-badges-backend@0.2.2-next.1 + - @backstage/plugin-azure-devops-backend@0.3.26-next.1 + - @backstage/plugin-devtools-backend@0.1.2-next.1 + - @backstage/plugin-linguist-backend@0.3.1-next.1 + - @backstage/plugin-auth-backend@0.18.5-next.1 + - example-app@0.2.85-next.1 + - @backstage/config@1.0.8 + +## 0.2.85-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.1-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.5-next.0 + - @backstage/plugin-catalog-backend@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.4.0-next.0 + - @backstage/plugin-kubernetes-backend@0.11.2-next.0 + - example-app@0.2.85-next.0 + - @backstage/backend-tasks@0.5.4-next.0 + - @backstage/catalog-client@1.4.3-next.0 + - @backstage/catalog-model@1.4.1-next.0 + - @backstage/config@1.0.8 + - @backstage/integration@1.5.1-next.0 + - @backstage/plugin-adr-backend@0.3.5-next.0 + - @backstage/plugin-app-backend@0.3.47-next.0 + - @backstage/plugin-auth-backend@0.18.5-next.0 + - @backstage/plugin-auth-node@0.2.16-next.0 + - @backstage/plugin-azure-devops-backend@0.3.26-next.0 + - @backstage/plugin-azure-sites-backend@0.1.9-next.0 + - @backstage/plugin-badges-backend@0.2.2-next.0 + - @backstage/plugin-code-coverage-backend@0.2.13-next.0 + - @backstage/plugin-devtools-backend@0.1.2-next.0 + - @backstage/plugin-events-backend@0.2.8-next.0 + - @backstage/plugin-events-node@0.2.8-next.0 + - @backstage/plugin-explore-backend@0.0.9-next.0 + - @backstage/plugin-graphql-backend@0.1.37-next.0 + - @backstage/plugin-jenkins-backend@0.2.2-next.0 + - @backstage/plugin-kafka-backend@0.2.40-next.0 + - @backstage/plugin-lighthouse-backend@0.2.3-next.0 + - @backstage/plugin-linguist-backend@0.3.1-next.0 + - @backstage/plugin-nomad-backend@0.1.1-next.0 + - @backstage/plugin-permission-backend@0.5.22-next.0 + - @backstage/plugin-permission-common@0.7.7-next.0 + - @backstage/plugin-permission-node@0.7.10-next.0 + - @backstage/plugin-playlist-backend@0.3.3-next.0 + - @backstage/plugin-proxy-backend@0.2.41-next.0 + - @backstage/plugin-rollbar-backend@0.1.44-next.0 + - @backstage/plugin-scaffolder-backend@1.15.1-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.16-next.0 + - @backstage/plugin-search-backend@1.3.3-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.2-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.8-next.0 + - @backstage/plugin-search-backend-node@1.2.3-next.0 + - @backstage/plugin-search-common@1.2.5-next.0 + - @backstage/plugin-tech-insights-backend@0.5.13-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.31-next.0 + - @backstage/plugin-tech-insights-node@0.4.5-next.0 + - @backstage/plugin-techdocs-backend@1.6.4-next.0 + - @backstage/plugin-todo-backend@0.1.44-next.0 + +## 0.2.84 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.0 + - @backstage/catalog-client@1.4.2 + - @backstage/plugin-jenkins-backend@0.2.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3 + - @backstage/plugin-devtools-backend@0.1.1 + - @backstage/plugin-scaffolder-backend@1.15.0 + - @backstage/plugin-nomad-backend@0.1.0 + - @backstage/plugin-azure-sites-backend@0.1.8 + - @backstage/plugin-kubernetes-backend@0.11.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0 + - @backstage/plugin-badges-backend@0.2.1 + - @backstage/plugin-catalog-backend@1.10.0 + - @backstage/integration@1.5.0 + - @backstage/plugin-search-backend@1.3.2 + - @backstage/plugin-explore-backend@0.0.8 + - @backstage/catalog-model@1.4.0 + - @backstage/plugin-auth-backend@0.18.4 + - @backstage/plugin-adr-backend@0.3.4 + - @backstage/plugin-code-coverage-backend@0.2.12 + - @backstage/plugin-proxy-backend@0.2.40 + - @backstage/plugin-linguist-backend@0.3.0 + - @backstage/plugin-search-backend-module-pg@0.5.7 + - example-app@0.2.84 + - @backstage/backend-tasks@0.5.3 + - @backstage/plugin-app-backend@0.3.46 + - @backstage/plugin-auth-node@0.2.15 + - @backstage/plugin-azure-devops-backend@0.3.25 + - @backstage/plugin-catalog-node@1.3.7 + - @backstage/plugin-entity-feedback-backend@0.1.4 + - @backstage/plugin-events-backend@0.2.7 + - @backstage/plugin-graphql-backend@0.1.36 + - @backstage/plugin-kafka-backend@0.2.39 + - @backstage/plugin-lighthouse-backend@0.2.2 + - @backstage/plugin-permission-backend@0.5.21 + - @backstage/plugin-permission-node@0.7.9 + - @backstage/plugin-playlist-backend@0.3.2 + - @backstage/plugin-rollbar-backend@0.1.43 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.15 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.1 + - @backstage/plugin-search-backend-node@1.2.2 + - @backstage/plugin-tech-insights-backend@0.5.12 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30 + - @backstage/plugin-tech-insights-node@0.4.4 + - @backstage/plugin-techdocs-backend@1.6.3 + - @backstage/plugin-todo-backend@0.1.43 + - @backstage/config@1.0.8 + - @backstage/plugin-events-node@0.2.7 + - @backstage/plugin-permission-common@0.7.6 + - @backstage/plugin-search-common@1.2.4 + +## 0.2.84-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.15.0-next.3 + - @backstage/plugin-kubernetes-backend@0.11.1-next.3 + - @backstage/backend-common@0.19.0-next.2 + - @backstage/catalog-model@1.4.0-next.1 + - @backstage/plugin-catalog-backend@1.10.0-next.2 + - example-app@0.2.84-next.3 + - @backstage/backend-tasks@0.5.3-next.2 + - @backstage/catalog-client@1.4.2-next.2 + - @backstage/config@1.0.7 + - @backstage/integration@1.5.0-next.0 + - @backstage/plugin-adr-backend@0.3.4-next.2 + - @backstage/plugin-app-backend@0.3.46-next.2 + - @backstage/plugin-auth-backend@0.18.4-next.3 + - @backstage/plugin-auth-node@0.2.15-next.2 + - @backstage/plugin-azure-devops-backend@0.3.25-next.2 + - @backstage/plugin-azure-sites-backend@0.1.8-next.2 + - @backstage/plugin-badges-backend@0.2.1-next.3 + - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0-next.1 + - @backstage/plugin-catalog-node@1.3.7-next.2 + - @backstage/plugin-code-coverage-backend@0.2.12-next.3 + - @backstage/plugin-devtools-backend@0.1.1-next.2 + - @backstage/plugin-entity-feedback-backend@0.1.4-next.2 + - @backstage/plugin-events-backend@0.2.7-next.2 + - @backstage/plugin-events-node@0.2.7-next.2 + - @backstage/plugin-explore-backend@0.0.8-next.2 + - @backstage/plugin-graphql-backend@0.1.36-next.2 + - @backstage/plugin-jenkins-backend@0.2.1-next.2 + - @backstage/plugin-kafka-backend@0.2.39-next.2 + - @backstage/plugin-lighthouse-backend@0.2.2-next.2 + - @backstage/plugin-linguist-backend@0.3.0-next.2 + - @backstage/plugin-permission-backend@0.5.21-next.2 + - @backstage/plugin-permission-common@0.7.6-next.0 + - @backstage/plugin-permission-node@0.7.9-next.2 + - @backstage/plugin-playlist-backend@0.3.2-next.2 + - @backstage/plugin-proxy-backend@0.2.40-next.2 + - @backstage/plugin-rollbar-backend@0.1.43-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3-next.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.3 + - @backstage/plugin-search-backend@1.3.2-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.1-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.7-next.2 + - @backstage/plugin-search-backend-node@1.2.2-next.2 + - @backstage/plugin-search-common@1.2.4-next.0 + - @backstage/plugin-tech-insights-backend@0.5.12-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30-next.2 + - @backstage/plugin-tech-insights-node@0.4.4-next.2 + - @backstage/plugin-techdocs-backend@1.6.3-next.2 + - @backstage/plugin-todo-backend@0.1.43-next.2 + +## 0.2.84-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.11.1-next.2 + - @backstage/plugin-badges-backend@0.2.1-next.2 + - @backstage/plugin-scaffolder-backend@1.15.0-next.2 + - @backstage/plugin-auth-backend@0.18.4-next.2 + - @backstage/plugin-code-coverage-backend@0.2.12-next.2 + - example-app@0.2.84-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.2 + - @backstage/config@1.0.7 + +## 0.2.84-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.0-next.1 + - @backstage/plugin-jenkins-backend@0.2.1-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3-next.1 + - @backstage/plugin-devtools-backend@0.1.1-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0-next.0 + - @backstage/plugin-catalog-backend@1.9.2-next.1 + - @backstage/integration@1.5.0-next.0 + - @backstage/plugin-adr-backend@0.3.4-next.1 + - @backstage/plugin-proxy-backend@0.2.40-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.7-next.1 + - @backstage/catalog-model@1.4.0-next.0 + - @backstage/plugin-scaffolder-backend@1.15.0-next.1 + - @backstage/backend-tasks@0.5.3-next.1 + - @backstage/plugin-app-backend@0.3.46-next.1 + - @backstage/plugin-auth-backend@0.18.4-next.1 + - @backstage/plugin-auth-node@0.2.15-next.1 + - @backstage/plugin-azure-devops-backend@0.3.25-next.1 + - @backstage/plugin-azure-sites-backend@0.1.8-next.1 + - @backstage/plugin-badges-backend@0.2.1-next.1 + - @backstage/plugin-catalog-node@1.3.7-next.1 + - @backstage/plugin-code-coverage-backend@0.2.12-next.1 + - @backstage/plugin-entity-feedback-backend@0.1.4-next.1 + - @backstage/plugin-events-backend@0.2.7-next.1 + - @backstage/plugin-explore-backend@0.0.8-next.1 + - @backstage/plugin-graphql-backend@0.1.36-next.1 + - @backstage/plugin-kafka-backend@0.2.39-next.1 + - @backstage/plugin-kubernetes-backend@0.11.1-next.1 + - @backstage/plugin-lighthouse-backend@0.2.2-next.1 + - @backstage/plugin-linguist-backend@0.3.0-next.1 + - @backstage/plugin-permission-backend@0.5.21-next.1 + - @backstage/plugin-permission-node@0.7.9-next.1 + - @backstage/plugin-playlist-backend@0.3.2-next.1 + - @backstage/plugin-rollbar-backend@0.1.43-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.1 + - @backstage/plugin-search-backend@1.3.2-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.1-next.1 + - @backstage/plugin-search-backend-node@1.2.2-next.1 + - @backstage/plugin-tech-insights-backend@0.5.12-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30-next.1 + - @backstage/plugin-tech-insights-node@0.4.4-next.1 + - @backstage/plugin-techdocs-backend@1.6.3-next.1 + - @backstage/plugin-todo-backend@0.1.43-next.1 + - example-app@0.2.84-next.1 + - @backstage/catalog-client@1.4.2-next.1 + - @backstage/plugin-permission-common@0.7.6-next.0 + - @backstage/plugin-events-node@0.2.7-next.1 + - @backstage/config@1.0.7 + - @backstage/plugin-search-common@1.2.4-next.0 + +## 0.2.84-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.4.2-next.0 + - @backstage/plugin-scaffolder-backend@1.14.1-next.0 + - @backstage/plugin-jenkins-backend@0.2.1-next.0 + - @backstage/plugin-linguist-backend@0.3.0-next.0 + - @backstage/plugin-devtools-backend@0.1.1-next.0 + - @backstage/plugin-adr-backend@0.3.4-next.0 + - @backstage/plugin-auth-backend@0.18.4-next.0 + - @backstage/plugin-badges-backend@0.2.1-next.0 + - @backstage/plugin-catalog-backend@1.9.2-next.0 + - @backstage/plugin-catalog-node@1.3.7-next.0 + - @backstage/plugin-code-coverage-backend@0.2.12-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.4-next.0 + - @backstage/plugin-kubernetes-backend@0.11.1-next.0 + - @backstage/plugin-lighthouse-backend@0.2.2-next.0 + - @backstage/plugin-playlist-backend@0.3.2-next.0 + - @backstage/plugin-tech-insights-backend@0.5.12-next.0 + - @backstage/plugin-techdocs-backend@1.6.3-next.0 + - @backstage/plugin-todo-backend@0.1.43-next.0 + - example-app@0.2.84-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.0 + - @backstage/backend-common@0.18.6-next.0 + - @backstage/integration@1.4.5 + - @backstage/plugin-app-backend@0.3.46-next.0 + - @backstage/plugin-explore-backend@0.0.8-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.3-next.0 + - @backstage/catalog-model@1.3.0 + - @backstage/plugin-auth-node@0.2.15-next.0 + - @backstage/plugin-azure-devops-backend@0.3.25-next.0 + - @backstage/plugin-azure-sites-backend@0.1.8-next.0 + - @backstage/plugin-events-backend@0.2.7-next.0 + - @backstage/plugin-events-node@0.2.7-next.0 + - @backstage/plugin-graphql-backend@0.1.36-next.0 + - @backstage/plugin-kafka-backend@0.2.39-next.0 + - @backstage/plugin-permission-backend@0.5.21-next.0 + - @backstage/plugin-permission-common@0.7.5 + - @backstage/plugin-permission-node@0.7.9-next.0 + - @backstage/plugin-proxy-backend@0.2.40-next.0 + - @backstage/plugin-rollbar-backend@0.1.43-next.0 + - @backstage/plugin-search-backend@1.3.2-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.1-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.7-next.0 + - @backstage/plugin-search-backend-node@1.2.2-next.0 + - @backstage/plugin-search-common@1.2.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30-next.0 + - @backstage/plugin-tech-insights-node@0.4.4-next.0 + +## 0.2.83 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.14.0 + - @backstage/plugin-devtools-backend@0.1.0 + - @backstage/plugin-catalog-backend@1.9.1 + - @backstage/backend-common@0.18.5 + - @backstage/plugin-kubernetes-backend@0.11.0 + - @backstage/plugin-auth-backend@0.18.3 + - @backstage/plugin-badges-backend@0.2.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.0 + - @backstage/integration@1.4.5 + - @backstage/plugin-todo-backend@0.1.42 + - @backstage/plugin-jenkins-backend@0.2.0 + - @backstage/plugin-azure-sites-backend@0.1.7 + - @backstage/plugin-permission-node@0.7.8 + - @backstage/plugin-search-backend@1.3.1 + - example-app@0.2.83 + - @backstage/backend-tasks@0.5.2 + - @backstage/plugin-app-backend@0.3.45 + - @backstage/plugin-auth-node@0.2.14 + - @backstage/plugin-catalog-node@1.3.6 + - @backstage/plugin-entity-feedback-backend@0.1.3 + - @backstage/plugin-events-backend@0.2.6 + - @backstage/plugin-playlist-backend@0.3.1 + - @backstage/plugin-rollbar-backend@0.1.42 + - @backstage/plugin-search-backend-module-pg@0.5.6 + - @backstage/plugin-tech-insights-backend@0.5.11 + - @backstage/plugin-techdocs-backend@1.6.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.14 + - @backstage/plugin-adr-backend@0.3.3 + - @backstage/plugin-azure-devops-backend@0.3.24 + - @backstage/plugin-code-coverage-backend@0.2.11 + - @backstage/plugin-explore-backend@0.0.7 + - @backstage/plugin-graphql-backend@0.1.35 + - @backstage/plugin-kafka-backend@0.2.38 + - @backstage/plugin-lighthouse-backend@0.2.1 + - @backstage/plugin-linguist-backend@0.2.2 + - @backstage/plugin-permission-backend@0.5.20 + - @backstage/plugin-proxy-backend@0.2.39 + - @backstage/plugin-search-backend-node@1.2.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.29 + - @backstage/plugin-tech-insights-node@0.4.3 + - @backstage/catalog-client@1.4.1 + - @backstage/catalog-model@1.3.0 + - @backstage/config@1.0.7 + - @backstage/plugin-events-node@0.2.6 + - @backstage/plugin-permission-common@0.7.5 + - @backstage/plugin-search-common@1.2.3 + +## 0.2.83-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-devtools-backend@0.1.0-next.0 + - @backstage/plugin-catalog-backend@1.9.1-next.2 + - @backstage/plugin-badges-backend@0.2.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.0-next.2 + - @backstage/plugin-kubernetes-backend@0.11.0-next.2 + - @backstage/plugin-auth-backend@0.18.3-next.2 + - @backstage/plugin-search-backend@1.3.1-next.2 + - example-app@0.2.83-next.2 + - @backstage/plugin-scaffolder-backend@1.13.2-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.14-next.2 + - @backstage/config@1.0.7 + +## 0.2.83-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.5-next.1 + - @backstage/plugin-kubernetes-backend@0.11.0-next.1 + - @backstage/plugin-catalog-backend@1.9.1-next.1 + - @backstage/plugin-jenkins-backend@0.1.35-next.1 + - @backstage/plugin-scaffolder-backend@1.13.2-next.1 + - example-app@0.2.83-next.1 + - @backstage/backend-tasks@0.5.2-next.1 + - @backstage/plugin-adr-backend@0.3.3-next.1 + - @backstage/plugin-app-backend@0.3.45-next.1 + - @backstage/plugin-auth-backend@0.18.3-next.1 + - @backstage/plugin-auth-node@0.2.14-next.1 + - @backstage/plugin-azure-devops-backend@0.3.24-next.1 + - @backstage/plugin-azure-sites-backend@0.1.7-next.1 + - @backstage/plugin-badges-backend@0.1.39-next.1 + - @backstage/plugin-catalog-node@1.3.6-next.1 + - @backstage/plugin-code-coverage-backend@0.2.11-next.1 + - @backstage/plugin-entity-feedback-backend@0.1.3-next.1 + - @backstage/plugin-events-backend@0.2.6-next.1 + - @backstage/plugin-explore-backend@0.0.7-next.1 + - @backstage/plugin-graphql-backend@0.1.35-next.1 + - @backstage/plugin-kafka-backend@0.2.38-next.1 + - @backstage/plugin-lighthouse-backend@0.2.1-next.1 + - @backstage/plugin-linguist-backend@0.2.2-next.1 + - @backstage/plugin-permission-backend@0.5.20-next.1 + - @backstage/plugin-permission-node@0.7.8-next.1 + - @backstage/plugin-playlist-backend@0.3.1-next.1 + - @backstage/plugin-proxy-backend@0.2.39-next.1 + - @backstage/plugin-rollbar-backend@0.1.42-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.14-next.1 + - @backstage/plugin-search-backend@1.3.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.2.1-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.6-next.1 + - @backstage/plugin-search-backend-node@1.2.1-next.1 + - @backstage/plugin-tech-insights-backend@0.5.11-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.29-next.1 + - @backstage/plugin-tech-insights-node@0.4.3-next.1 + - @backstage/plugin-techdocs-backend@1.6.2-next.1 + - @backstage/plugin-todo-backend@0.1.42-next.1 + - @backstage/config@1.0.7 + - @backstage/plugin-events-node@0.2.6-next.1 + +## 0.2.83-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.5-next.0 + - @backstage/integration@1.4.5-next.0 + - @backstage/plugin-permission-node@0.7.8-next.0 + - @backstage/plugin-scaffolder-backend@1.13.2-next.0 + - @backstage/plugin-kubernetes-backend@0.11.0-next.0 + - @backstage/backend-tasks@0.5.2-next.0 + - @backstage/plugin-app-backend@0.3.45-next.0 + - @backstage/plugin-auth-backend@0.18.3-next.0 + - @backstage/plugin-auth-node@0.2.14-next.0 + - @backstage/plugin-catalog-backend@1.9.1-next.0 + - @backstage/plugin-catalog-node@1.3.6-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.3-next.0 + - @backstage/plugin-events-backend@0.2.6-next.0 + - @backstage/plugin-playlist-backend@0.3.1-next.0 + - @backstage/plugin-rollbar-backend@0.1.42-next.0 + - @backstage/plugin-search-backend@1.3.1-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.6-next.0 + - @backstage/plugin-tech-insights-backend@0.5.11-next.0 + - @backstage/plugin-techdocs-backend@1.6.2-next.0 + - example-app@0.2.83-next.0 + - @backstage/plugin-adr-backend@0.3.3-next.0 + - @backstage/plugin-azure-devops-backend@0.3.24-next.0 + - @backstage/plugin-azure-sites-backend@0.1.7-next.0 + - @backstage/plugin-badges-backend@0.1.39-next.0 + - @backstage/plugin-code-coverage-backend@0.2.11-next.0 + - @backstage/plugin-explore-backend@0.0.7-next.0 + - @backstage/plugin-graphql-backend@0.1.35-next.0 + - @backstage/plugin-jenkins-backend@0.1.35-next.0 + - @backstage/plugin-kafka-backend@0.2.38-next.0 + - @backstage/plugin-lighthouse-backend@0.2.1-next.0 + - @backstage/plugin-linguist-backend@0.2.2-next.0 + - @backstage/plugin-permission-backend@0.5.20-next.0 + - @backstage/plugin-proxy-backend@0.2.39-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.14-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.2.1-next.0 + - @backstage/plugin-search-backend-node@1.2.1-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.29-next.0 + - @backstage/plugin-tech-insights-node@0.4.3-next.0 + - @backstage/plugin-todo-backend@0.1.42-next.0 + - @backstage/catalog-client@1.4.1 + - @backstage/catalog-model@1.3.0 + - @backstage/config@1.0.7 + - @backstage/plugin-events-node@0.2.6-next.0 + - @backstage/plugin-permission-common@0.7.5 + - @backstage/plugin-search-common@1.2.3 + +## 0.2.82 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.10.0 + - @backstage/backend-common@0.18.4 + - @backstage/plugin-scaffolder-backend@1.13.0 + - @backstage/plugin-catalog-backend@1.9.0 + - @backstage/plugin-code-coverage-backend@0.2.10 + - @backstage/catalog-client@1.4.1 + - @backstage/plugin-permission-node@0.7.7 + - @backstage/plugin-permission-backend@0.5.19 + - @backstage/plugin-entity-feedback-backend@0.1.2 + - @backstage/plugin-rollbar-backend@0.1.41 + - @backstage/plugin-search-backend@1.3.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.2.0 + - @backstage/plugin-search-backend-module-pg@0.5.5 + - @backstage/plugin-auth-backend@0.18.2 + - @backstage/plugin-lighthouse-backend@0.2.0 + - @backstage/plugin-permission-common@0.7.5 + - @backstage/plugin-playlist-backend@0.3.0 + - @backstage/backend-tasks@0.5.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28 + - @backstage/plugin-adr-backend@0.3.2 + - @backstage/plugin-graphql-backend@0.1.34 + - @backstage/catalog-model@1.3.0 + - @backstage/plugin-techdocs-backend@1.6.1 + - @backstage/plugin-explore-backend@0.0.6 + - @backstage/plugin-events-backend@0.2.5 + - @backstage/plugin-search-backend-node@1.2.0 + - @backstage/integration@1.4.4 + - example-app@0.2.82 + - @backstage/plugin-app-backend@0.3.44 + - @backstage/plugin-auth-node@0.2.13 + - @backstage/plugin-azure-devops-backend@0.3.23 + - @backstage/plugin-azure-sites-backend@0.1.6 + - @backstage/plugin-badges-backend@0.1.38 + - @backstage/plugin-catalog-node@1.3.5 + - @backstage/plugin-jenkins-backend@0.1.34 + - @backstage/plugin-kafka-backend@0.2.37 + - @backstage/plugin-linguist-backend@0.2.1 + - @backstage/plugin-proxy-backend@0.2.38 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.12 + - @backstage/plugin-tech-insights-backend@0.5.10 + - @backstage/plugin-tech-insights-node@0.4.2 + - @backstage/plugin-todo-backend@0.1.41 + - @backstage/config@1.0.7 + - @backstage/plugin-events-node@0.2.5 + - @backstage/plugin-search-common@1.2.3 + +## 0.2.82-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.10.0-next.3 + - @backstage/plugin-catalog-backend@1.9.0-next.3 + - @backstage/plugin-code-coverage-backend@0.2.10-next.3 + - @backstage/plugin-lighthouse-backend@0.2.0-next.3 + - @backstage/plugin-auth-backend@0.18.2-next.3 + - @backstage/plugin-scaffolder-backend@1.13.0-next.3 + - @backstage/plugin-search-backend-module-elasticsearch@1.2.0-next.3 + - @backstage/catalog-model@1.3.0-next.0 + - @backstage/plugin-events-backend@0.2.5-next.3 + - example-app@0.2.82-next.3 + - @backstage/backend-common@0.18.4-next.2 + - @backstage/backend-tasks@0.5.1-next.2 + - @backstage/catalog-client@1.4.1-next.1 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.4-next.0 + - @backstage/plugin-adr-backend@0.3.2-next.3 + - @backstage/plugin-app-backend@0.3.44-next.2 + - @backstage/plugin-auth-node@0.2.13-next.2 + - @backstage/plugin-azure-devops-backend@0.3.23-next.2 + - @backstage/plugin-azure-sites-backend@0.1.6-next.2 + - @backstage/plugin-badges-backend@0.1.38-next.3 + - @backstage/plugin-catalog-node@1.3.5-next.3 + - @backstage/plugin-entity-feedback-backend@0.1.2-next.3 + - @backstage/plugin-events-node@0.2.5-next.2 + - @backstage/plugin-explore-backend@0.0.6-next.2 + - @backstage/plugin-graphql-backend@0.1.34-next.3 + - @backstage/plugin-jenkins-backend@0.1.34-next.3 + - @backstage/plugin-kafka-backend@0.2.37-next.3 + - @backstage/plugin-linguist-backend@0.2.1-next.3 + - @backstage/plugin-permission-backend@0.5.19-next.2 + - @backstage/plugin-permission-common@0.7.5-next.0 + - @backstage/plugin-permission-node@0.7.7-next.2 + - @backstage/plugin-playlist-backend@0.2.7-next.3 + - @backstage/plugin-proxy-backend@0.2.38-next.2 + - @backstage/plugin-rollbar-backend@0.1.41-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.3 + - @backstage/plugin-search-backend@1.3.0-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.5-next.2 + - @backstage/plugin-search-backend-node@1.2.0-next.2 + - @backstage/plugin-search-common@1.2.3-next.0 + - @backstage/plugin-tech-insights-backend@0.5.10-next.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.2 + - @backstage/plugin-tech-insights-node@0.4.2-next.2 + - @backstage/plugin-techdocs-backend@1.6.1-next.3 + - @backstage/plugin-todo-backend@0.1.41-next.3 + +## 0.2.82-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.10.0-next.2 + - @backstage/plugin-catalog-backend@1.8.1-next.2 + - @backstage/backend-common@0.18.4-next.2 + - @backstage/catalog-client@1.4.1-next.0 + - @backstage/plugin-permission-node@0.7.7-next.2 + - @backstage/plugin-permission-backend@0.5.19-next.2 + - @backstage/plugin-rollbar-backend@0.1.41-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.2 + - @backstage/plugin-scaffolder-backend@1.13.0-next.2 + - example-app@0.2.82-next.2 + - @backstage/backend-tasks@0.5.1-next.2 + - @backstage/catalog-model@1.2.1 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.4-next.0 + - @backstage/plugin-adr-backend@0.3.2-next.2 + - @backstage/plugin-app-backend@0.3.44-next.2 + - @backstage/plugin-auth-backend@0.18.2-next.2 + - @backstage/plugin-auth-node@0.2.13-next.2 + - @backstage/plugin-azure-devops-backend@0.3.23-next.2 + - @backstage/plugin-azure-sites-backend@0.1.6-next.2 + - @backstage/plugin-badges-backend@0.1.38-next.2 + - @backstage/plugin-catalog-node@1.3.5-next.2 + - @backstage/plugin-code-coverage-backend@0.2.10-next.2 + - @backstage/plugin-entity-feedback-backend@0.1.2-next.2 + - @backstage/plugin-events-backend@0.2.5-next.2 + - @backstage/plugin-events-node@0.2.5-next.2 + - @backstage/plugin-explore-backend@0.0.6-next.2 + - @backstage/plugin-graphql-backend@0.1.34-next.2 + - @backstage/plugin-jenkins-backend@0.1.34-next.2 + - @backstage/plugin-kafka-backend@0.2.37-next.2 + - @backstage/plugin-lighthouse-backend@0.1.2-next.2 + - @backstage/plugin-linguist-backend@0.2.1-next.2 + - @backstage/plugin-permission-common@0.7.5-next.0 + - @backstage/plugin-playlist-backend@0.2.7-next.2 + - @backstage/plugin-proxy-backend@0.2.38-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.2 + - @backstage/plugin-search-backend@1.3.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.2.0-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.5-next.2 + - @backstage/plugin-search-backend-node@1.2.0-next.2 + - @backstage/plugin-search-common@1.2.3-next.0 + - @backstage/plugin-tech-insights-backend@0.5.10-next.2 + - @backstage/plugin-tech-insights-node@0.4.2-next.2 + - @backstage/plugin-techdocs-backend@1.6.1-next.2 + - @backstage/plugin-todo-backend@0.1.41-next.2 + +## 0.2.82-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend@1.3.0-next.1 + - @backstage/plugin-scaffolder-backend@1.13.0-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.2.0-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.5-next.1 + - @backstage/plugin-permission-node@0.7.7-next.1 + - @backstage/plugin-permission-backend@0.5.19-next.1 + - @backstage/plugin-permission-common@0.7.5-next.0 + - @backstage/plugin-playlist-backend@0.2.7-next.1 + - @backstage/plugin-catalog-backend@1.8.1-next.1 + - @backstage/backend-tasks@0.5.1-next.1 + - @backstage/plugin-adr-backend@0.3.2-next.1 + - @backstage/plugin-kubernetes-backend@0.10.0-next.1 + - @backstage/plugin-techdocs-backend@1.6.1-next.1 + - @backstage/plugin-explore-backend@0.0.6-next.1 + - @backstage/plugin-search-backend-node@1.2.0-next.1 + - @backstage/integration@1.4.4-next.0 + - @backstage/plugin-auth-backend@0.18.2-next.1 + - example-app@0.2.82-next.1 + - @backstage/backend-common@0.18.4-next.1 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/config@1.0.7 + - @backstage/plugin-app-backend@0.3.44-next.1 + - @backstage/plugin-auth-node@0.2.13-next.1 + - @backstage/plugin-azure-devops-backend@0.3.23-next.1 + - @backstage/plugin-azure-sites-backend@0.1.6-next.1 + - @backstage/plugin-badges-backend@0.1.38-next.1 + - @backstage/plugin-catalog-node@1.3.5-next.1 + - @backstage/plugin-code-coverage-backend@0.2.10-next.1 + - @backstage/plugin-entity-feedback-backend@0.1.2-next.1 + - @backstage/plugin-events-backend@0.2.5-next.1 + - @backstage/plugin-events-node@0.2.5-next.1 + - @backstage/plugin-graphql-backend@0.1.34-next.1 + - @backstage/plugin-jenkins-backend@0.1.34-next.1 + - @backstage/plugin-kafka-backend@0.2.37-next.1 + - @backstage/plugin-lighthouse-backend@0.1.2-next.1 + - @backstage/plugin-linguist-backend@0.2.1-next.1 + - @backstage/plugin-proxy-backend@0.2.38-next.1 + - @backstage/plugin-rollbar-backend@0.1.41-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.1 + - @backstage/plugin-search-common@1.2.3-next.0 + - @backstage/plugin-tech-insights-backend@0.5.10-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.1 + - @backstage/plugin-tech-insights-node@0.4.2-next.1 + - @backstage/plugin-todo-backend@0.1.41-next.1 + +## 0.2.82-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-kubernetes-backend@0.10.0-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.2-next.0 + - @backstage/plugin-auth-backend@0.18.2-next.0 + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/plugin-graphql-backend@0.1.34-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.0 + - example-app@0.2.82-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-adr-backend@0.3.2-next.0 + - @backstage/plugin-app-backend@0.3.44-next.0 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-azure-devops-backend@0.3.23-next.0 + - @backstage/plugin-azure-sites-backend@0.1.6-next.0 + - @backstage/plugin-badges-backend@0.1.38-next.0 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-code-coverage-backend@0.2.10-next.0 + - @backstage/plugin-events-backend@0.2.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + - @backstage/plugin-explore-backend@0.0.6-next.0 + - @backstage/plugin-jenkins-backend@0.1.34-next.0 + - @backstage/plugin-kafka-backend@0.2.37-next.0 + - @backstage/plugin-lighthouse-backend@0.1.2-next.0 + - @backstage/plugin-linguist-backend@0.2.1-next.0 + - @backstage/plugin-permission-backend@0.5.19-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-playlist-backend@0.2.7-next.0 + - @backstage/plugin-proxy-backend@0.2.38-next.0 + - @backstage/plugin-rollbar-backend@0.1.41-next.0 + - @backstage/plugin-search-backend@1.2.5-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.5-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.5-next.0 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + - @backstage/plugin-tech-insights-backend@0.5.10-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.0 + - @backstage/plugin-tech-insights-node@0.4.2-next.0 + - @backstage/plugin-techdocs-backend@1.6.1-next.0 + - @backstage/plugin-todo-backend@0.1.41-next.0 + +## 0.2.81 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.0 + - @backstage/plugin-catalog-backend@1.8.0 + - @backstage/catalog-client@1.4.0 + - @backstage/plugin-todo-backend@0.1.40 + - @backstage/plugin-permission-node@0.7.6 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.4 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27 + - @backstage/plugin-auth-node@0.2.12 + - @backstage/plugin-techdocs-backend@1.6.0 + - @backstage/backend-tasks@0.5.0 + - @backstage/plugin-tech-insights-backend@0.5.9 + - @backstage/plugin-adr-backend@0.3.1 + - @backstage/plugin-auth-backend@0.18.1 + - @backstage/backend-common@0.18.3 + - @backstage/plugin-linguist-backend@0.2.0 + - @backstage/plugin-catalog-node@1.3.4 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-events-backend@0.2.4 + - @backstage/plugin-app-backend@0.3.43 + - @backstage/plugin-events-node@0.2.4 + - @backstage/integration@1.4.3 + - @backstage/plugin-azure-devops-backend@0.3.22 + - @backstage/plugin-azure-sites-backend@0.1.5 + - @backstage/plugin-code-coverage-backend@0.2.9 + - @backstage/plugin-entity-feedback-backend@0.1.1 + - @backstage/plugin-explore-backend@0.0.5 + - @backstage/plugin-graphql-backend@0.1.33 + - @backstage/plugin-jenkins-backend@0.1.33 + - @backstage/plugin-kubernetes-backend@0.9.4 + - @backstage/plugin-permission-backend@0.5.18 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-playlist-backend@0.2.6 + - @backstage/plugin-proxy-backend@0.2.37 + - @backstage/plugin-rollbar-backend@0.1.40 + - @backstage/plugin-lighthouse-backend@0.1.1 + - @backstage/config@1.0.7 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.11 + - @backstage/plugin-badges-backend@0.1.37 + - example-app@0.2.81 + - @backstage/plugin-search-backend@1.2.4 + - @backstage/plugin-kafka-backend@0.2.36 + - @backstage/plugin-search-backend-module-pg@0.5.4 + - @backstage/plugin-search-backend-node@1.1.4 + - @backstage/plugin-search-common@1.2.2 + - @backstage/plugin-tech-insights-node@0.4.1 + +## 0.2.81-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.4-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27-next.2 + - @backstage/plugin-auth-node@0.2.12-next.2 + - @backstage/backend-tasks@0.5.0-next.2 + - @backstage/plugin-adr-backend@0.3.1-next.2 + - @backstage/backend-common@0.18.3-next.2 + - @backstage/plugin-linguist-backend@0.2.0-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.11-next.2 + - example-app@0.2.81-next.2 + - @backstage/plugin-techdocs-backend@1.5.4-next.2 + - @backstage/plugin-auth-backend@0.18.1-next.2 + - @backstage/plugin-entity-feedback-backend@0.1.1-next.2 + - @backstage/plugin-jenkins-backend@0.1.33-next.2 + - @backstage/plugin-kubernetes-backend@0.9.4-next.2 + - @backstage/plugin-permission-backend@0.5.18-next.2 + - @backstage/plugin-permission-node@0.7.6-next.2 + - @backstage/plugin-playlist-backend@0.2.6-next.2 + - @backstage/plugin-search-backend@1.2.4-next.2 + - @backstage/plugin-lighthouse-backend@0.1.1-next.2 + - @backstage/plugin-search-backend-node@1.1.4-next.2 + - @backstage/plugin-tech-insights-backend@0.5.9-next.2 + - @backstage/plugin-tech-insights-node@0.4.1-next.2 + - @backstage/plugin-app-backend@0.3.43-next.2 + - @backstage/plugin-azure-devops-backend@0.3.22-next.2 + - @backstage/plugin-azure-sites-backend@0.1.5-next.2 + - @backstage/plugin-badges-backend@0.1.37-next.2 + - @backstage/plugin-catalog-backend@1.8.0-next.2 + - @backstage/plugin-catalog-node@1.3.4-next.2 + - @backstage/plugin-code-coverage-backend@0.2.9-next.2 + - @backstage/plugin-events-backend@0.2.4-next.2 + - @backstage/plugin-explore-backend@0.0.5-next.2 + - @backstage/plugin-graphql-backend@0.1.33-next.2 + - @backstage/plugin-kafka-backend@0.2.36-next.2 + - @backstage/plugin-proxy-backend@0.2.37-next.2 + - @backstage/plugin-rollbar-backend@0.1.40-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.4-next.2 + - @backstage/plugin-todo-backend@0.1.40-next.2 + - @backstage/plugin-events-node@0.2.4-next.2 + - @backstage/config@1.0.7-next.0 + - @backstage/integration@1.4.3-next.0 + +## 0.2.81-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.0-next.1 + - @backstage/plugin-permission-node@0.7.6-next.1 + - @backstage/plugin-techdocs-backend@1.5.4-next.1 + - @backstage/plugin-auth-backend@0.18.1-next.1 + - @backstage/backend-common@0.18.3-next.1 + - @backstage/catalog-client@1.4.0-next.1 + - @backstage/integration@1.4.3-next.0 + - @backstage/plugin-adr-backend@0.3.1-next.1 + - @backstage/plugin-app-backend@0.3.43-next.1 + - @backstage/plugin-auth-node@0.2.12-next.1 + - @backstage/plugin-azure-devops-backend@0.3.22-next.1 + - @backstage/plugin-azure-sites-backend@0.1.5-next.1 + - @backstage/plugin-catalog-backend@1.8.0-next.1 + - @backstage/plugin-code-coverage-backend@0.2.9-next.1 + - @backstage/plugin-entity-feedback-backend@0.1.1-next.1 + - @backstage/plugin-explore-backend@0.0.5-next.1 + - @backstage/plugin-graphql-backend@0.1.33-next.1 + - @backstage/plugin-jenkins-backend@0.1.33-next.1 + - @backstage/plugin-kubernetes-backend@0.9.4-next.1 + - @backstage/plugin-linguist-backend@0.2.0-next.1 + - @backstage/plugin-permission-backend@0.5.18-next.1 + - @backstage/plugin-permission-common@0.7.4-next.0 + - @backstage/plugin-playlist-backend@0.2.6-next.1 + - @backstage/plugin-proxy-backend@0.2.37-next.1 + - @backstage/plugin-rollbar-backend@0.1.40-next.1 + - @backstage/plugin-todo-backend@0.1.40-next.1 + - @backstage/plugin-lighthouse-backend@0.1.1-next.1 + - @backstage/backend-tasks@0.4.4-next.1 + - @backstage/config@1.0.7-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.11-next.1 + - @backstage/plugin-search-backend@1.2.4-next.1 + - example-app@0.2.81-next.1 + - @backstage/catalog-model@1.2.1-next.1 + - @backstage/plugin-badges-backend@0.1.37-next.1 + - @backstage/plugin-catalog-node@1.3.4-next.1 + - @backstage/plugin-events-backend@0.2.4-next.1 + - @backstage/plugin-events-node@0.2.4-next.1 + - @backstage/plugin-kafka-backend@0.2.36-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.4-next.1 + - @backstage/plugin-search-backend-node@1.1.4-next.1 + - @backstage/plugin-search-common@1.2.2-next.0 + - @backstage/plugin-tech-insights-backend@0.5.9-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27-next.1 + - @backstage/plugin-tech-insights-node@0.4.1-next.1 + +## 0.2.81-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.4.0-next.0 + - @backstage/plugin-todo-backend@0.1.40-next.0 + - @backstage/plugin-scaffolder-backend@1.11.1-next.0 + - @backstage/plugin-catalog-backend@1.8.0-next.0 + - @backstage/plugin-tech-insights-backend@0.5.9-next.0 + - @backstage/plugin-linguist-backend@0.2.0-next.0 + - @backstage/plugin-adr-backend@0.3.1-next.0 + - @backstage/backend-tasks@0.4.4-next.0 + - @backstage/plugin-techdocs-backend@1.5.4-next.0 + - @backstage/backend-common@0.18.3-next.0 + - @backstage/catalog-model@1.2.1-next.0 + - @backstage/plugin-events-backend@0.2.4-next.0 + - @backstage/plugin-catalog-node@1.3.4-next.0 + - @backstage/plugin-app-backend@0.3.43-next.0 + - @backstage/plugin-events-node@0.2.4-next.0 + - @backstage/plugin-proxy-backend@0.2.37-next.0 + - @backstage/plugin-auth-backend@0.18.1-next.0 + - @backstage/plugin-badges-backend@0.1.37-next.0 + - @backstage/plugin-code-coverage-backend@0.2.9-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.1-next.0 + - @backstage/plugin-jenkins-backend@0.1.33-next.0 + - @backstage/plugin-kubernetes-backend@0.9.4-next.0 + - @backstage/plugin-lighthouse-backend@0.1.1-next.0 + - @backstage/plugin-playlist-backend@0.2.6-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.11-next.0 + - example-app@0.2.81-next.0 + - @backstage/config@1.0.6 + - @backstage/integration@1.4.2 + - @backstage/plugin-auth-node@0.2.12-next.0 + - @backstage/plugin-azure-devops-backend@0.3.22-next.0 + - @backstage/plugin-azure-sites-backend@0.1.5-next.0 + - @backstage/plugin-explore-backend@0.0.5-next.0 + - @backstage/plugin-graphql-backend@0.1.33-next.0 + - @backstage/plugin-kafka-backend@0.2.36-next.0 + - @backstage/plugin-permission-backend@0.5.18-next.0 + - @backstage/plugin-permission-common@0.7.3 + - @backstage/plugin-permission-node@0.7.6-next.0 + - @backstage/plugin-rollbar-backend@0.1.40-next.0 + - @backstage/plugin-search-backend@1.2.4-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.4-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.4-next.0 + - @backstage/plugin-search-backend-node@1.1.4-next.0 + - @backstage/plugin-search-common@1.2.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27-next.0 + - @backstage/plugin-tech-insights-node@0.4.1-next.0 + +## 0.2.80 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.7.2 + - @backstage/plugin-playlist-backend@0.2.5 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.3 + - @backstage/backend-common@0.18.2 + - @backstage/plugin-kubernetes-backend@0.9.3 + - @backstage/plugin-lighthouse-backend@0.1.0 + - @backstage/plugin-code-coverage-backend@0.2.8 + - @backstage/plugin-azure-devops-backend@0.3.21 + - @backstage/plugin-azure-sites-backend@0.1.4 + - @backstage/plugin-adr-backend@0.3.0 + - @backstage/plugin-tech-insights-backend@0.5.8 + - @backstage/plugin-tech-insights-node@0.4.0 + - @backstage/plugin-entity-feedback-backend@0.1.0 + - @backstage/plugin-search-backend@1.2.3 + - @backstage/plugin-techdocs-backend@1.5.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.10 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26 + - @backstage/plugin-scaffolder-backend@1.11.0 + - @backstage/plugin-events-backend@0.2.3 + - @backstage/plugin-kafka-backend@0.2.35 + - @backstage/plugin-proxy-backend@0.2.36 + - @backstage/plugin-app-backend@0.3.42 + - @backstage/catalog-model@1.2.0 + - @backstage/plugin-auth-backend@0.18.0 + - @backstage/plugin-linguist-backend@0.1.0 + - @backstage/plugin-events-node@0.2.3 + - example-app@0.2.80 + - @backstage/plugin-catalog-node@1.3.3 + - @backstage/backend-tasks@0.4.3 + - @backstage/catalog-client@1.3.1 + - @backstage/config@1.0.6 + - @backstage/integration@1.4.2 + - @backstage/plugin-auth-node@0.2.11 + - @backstage/plugin-badges-backend@0.1.36 + - @backstage/plugin-explore-backend@0.0.4 + - @backstage/plugin-graphql-backend@0.1.32 + - @backstage/plugin-jenkins-backend@0.1.32 + - @backstage/plugin-permission-backend@0.5.17 + - @backstage/plugin-permission-common@0.7.3 + - @backstage/plugin-permission-node@0.7.5 + - @backstage/plugin-rollbar-backend@0.1.39 + - @backstage/plugin-search-backend-module-pg@0.5.3 + - @backstage/plugin-search-backend-node@1.1.3 + - @backstage/plugin-search-common@1.2.1 + - @backstage/plugin-todo-backend@0.1.39 + +## 0.2.80-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-lighthouse-backend@0.1.0-next.0 + - @backstage/backend-common@0.18.2-next.2 + - @backstage/plugin-catalog-backend@1.7.2-next.2 + - @backstage/plugin-search-backend@1.2.3-next.2 + - @backstage/plugin-scaffolder-backend@1.11.0-next.2 + - @backstage/plugin-events-backend@0.2.3-next.2 + - @backstage/plugin-kafka-backend@0.2.35-next.2 + - @backstage/plugin-proxy-backend@0.2.36-next.2 + - @backstage/plugin-app-backend@0.3.42-next.2 + - @backstage/catalog-model@1.2.0-next.1 + - @backstage/plugin-kubernetes-backend@0.9.3-next.2 + - @backstage/plugin-events-node@0.2.3-next.2 + - @backstage/plugin-catalog-node@1.3.3-next.2 + - @backstage/backend-tasks@0.4.3-next.2 + - @backstage/plugin-auth-backend@0.17.5-next.2 + - @backstage/plugin-auth-node@0.2.11-next.2 + - @backstage/plugin-permission-node@0.7.5-next.2 + - @backstage/plugin-playlist-backend@0.2.5-next.2 + - @backstage/plugin-rollbar-backend@0.1.39-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.3-next.2 + - @backstage/plugin-tech-insights-backend@0.5.8-next.2 + - @backstage/plugin-techdocs-backend@1.5.3-next.2 + - example-app@0.2.80-next.2 + - @backstage/catalog-client@1.3.1-next.1 + - @backstage/config@1.0.6 + - @backstage/integration@1.4.2 + - @backstage/plugin-adr-backend@0.2.7-next.2 + - @backstage/plugin-azure-devops-backend@0.3.21-next.2 + - @backstage/plugin-azure-sites-backend@0.1.4-next.2 + - @backstage/plugin-badges-backend@0.1.36-next.2 + - @backstage/plugin-code-coverage-backend@0.2.8-next.2 + - @backstage/plugin-explore-backend@0.0.4-next.2 + - @backstage/plugin-graphql-backend@0.1.32-next.2 + - @backstage/plugin-jenkins-backend@0.1.32-next.2 + - @backstage/plugin-permission-backend@0.5.17-next.2 + - @backstage/plugin-permission-common@0.7.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.2 + - @backstage/plugin-search-backend-node@1.1.3-next.2 + - @backstage/plugin-search-common@1.2.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.2 + - @backstage/plugin-tech-insights-node@0.4.0-next.2 + - @backstage/plugin-todo-backend@0.1.39-next.2 + +## 0.2.80-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.7.2-next.1 + - @backstage/plugin-tech-insights-backend@0.5.8-next.1 + - @backstage/plugin-tech-insights-node@0.4.0-next.1 + - @backstage/plugin-azure-devops-backend@0.3.21-next.1 + - @backstage/backend-common@0.18.2-next.1 + - @backstage/plugin-kubernetes-backend@0.9.3-next.1 + - @backstage/plugin-scaffolder-backend@1.11.0-next.1 + - @backstage/plugin-playlist-backend@0.2.5-next.1 + - example-app@0.2.80-next.1 + - @backstage/backend-tasks@0.4.3-next.1 + - @backstage/catalog-client@1.3.1-next.0 + - @backstage/catalog-model@1.1.6-next.0 + - @backstage/config@1.0.6 + - @backstage/integration@1.4.2 + - @backstage/plugin-adr-backend@0.2.7-next.1 + - @backstage/plugin-app-backend@0.3.42-next.1 + - @backstage/plugin-auth-backend@0.17.5-next.1 + - @backstage/plugin-auth-node@0.2.11-next.1 + - @backstage/plugin-azure-sites-backend@0.1.4-next.1 + - @backstage/plugin-badges-backend@0.1.36-next.1 + - @backstage/plugin-catalog-node@1.3.3-next.1 + - @backstage/plugin-code-coverage-backend@0.2.8-next.1 + - @backstage/plugin-events-backend@0.2.3-next.1 + - @backstage/plugin-events-node@0.2.3-next.1 + - @backstage/plugin-explore-backend@0.0.4-next.1 + - @backstage/plugin-graphql-backend@0.1.32-next.1 + - @backstage/plugin-jenkins-backend@0.1.32-next.1 + - @backstage/plugin-kafka-backend@0.2.35-next.1 + - @backstage/plugin-permission-backend@0.5.17-next.1 + - @backstage/plugin-permission-common@0.7.3 + - @backstage/plugin-permission-node@0.7.5-next.1 + - @backstage/plugin-proxy-backend@0.2.36-next.1 + - @backstage/plugin-rollbar-backend@0.1.39-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.1 + - @backstage/plugin-search-backend@1.2.3-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.3-next.1 + - @backstage/plugin-search-backend-node@1.1.3-next.1 + - @backstage/plugin-search-common@1.2.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.1 + - @backstage/plugin-techdocs-backend@1.5.3-next.1 + - @backstage/plugin-todo-backend@0.1.39-next.1 + +## 0.2.80-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.9.3-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.0 + - @backstage/plugin-scaffolder-backend@1.11.0-next.0 + - @backstage/catalog-model@1.1.6-next.0 + - example-app@0.2.80-next.0 + - @backstage/plugin-techdocs-backend@1.5.3-next.0 + - @backstage/backend-common@0.18.2-next.0 + - @backstage/plugin-app-backend@0.3.42-next.0 + - @backstage/catalog-client@1.3.1-next.0 + - @backstage/plugin-adr-backend@0.2.7-next.0 + - @backstage/plugin-auth-backend@0.17.5-next.0 + - @backstage/plugin-badges-backend@0.1.36-next.0 + - @backstage/plugin-catalog-backend@1.7.2-next.0 + - @backstage/plugin-catalog-node@1.3.3-next.0 + - @backstage/plugin-code-coverage-backend@0.2.8-next.0 + - @backstage/plugin-jenkins-backend@0.1.32-next.0 + - @backstage/plugin-kafka-backend@0.2.35-next.0 + - @backstage/plugin-playlist-backend@0.2.5-next.0 + - @backstage/plugin-tech-insights-backend@0.5.8-next.0 + - @backstage/plugin-todo-backend@0.1.39-next.0 + - @backstage/backend-tasks@0.4.3-next.0 + - @backstage/plugin-auth-node@0.2.11-next.0 + - @backstage/plugin-events-backend@0.2.3-next.0 + - @backstage/plugin-permission-node@0.7.5-next.0 + - @backstage/plugin-rollbar-backend@0.1.39-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.3-next.0 + - @backstage/plugin-azure-devops-backend@0.3.21-next.0 + - @backstage/plugin-azure-sites-backend@0.1.4-next.0 + - @backstage/plugin-explore-backend@0.0.4-next.0 + - @backstage/plugin-graphql-backend@0.1.32-next.0 + - @backstage/plugin-permission-backend@0.5.17-next.0 + - @backstage/plugin-proxy-backend@0.2.36-next.0 + - @backstage/plugin-search-backend@1.2.3-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.0 + - @backstage/plugin-search-backend-node@1.1.3-next.0 + - @backstage/plugin-tech-insights-node@0.3.10-next.0 + - @backstage/plugin-events-node@0.2.3-next.0 + +## 0.2.79 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.10.0 + - @backstage/backend-common@0.18.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.8 + - @backstage/plugin-adr-backend@0.2.5 + - @backstage/catalog-model@1.1.5 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.1 + - @backstage/plugin-search-backend-node@1.1.1 + - @backstage/catalog-client@1.3.0 + - @backstage/plugin-explore-backend@0.0.2 + - @backstage/backend-tasks@0.4.1 + - @backstage/plugin-events-backend@0.2.1 + - @backstage/plugin-catalog-node@1.3.1 + - @backstage/plugin-app-backend@0.3.40 + - @backstage/plugin-code-coverage-backend@0.2.6 + - @backstage/plugin-catalog-backend@1.7.0 + - @backstage/plugin-tech-insights-backend@0.5.6 + - @backstage/plugin-kubernetes-backend@0.9.1 + - @backstage/config@1.0.6 + - @backstage/plugin-search-backend@1.2.1 + - @backstage/plugin-events-node@0.2.1 + - example-app@0.2.79 + - @backstage/integration@1.4.2 + - @backstage/plugin-auth-backend@0.17.3 + - @backstage/plugin-auth-node@0.2.9 + - @backstage/plugin-azure-devops-backend@0.3.19 + - @backstage/plugin-azure-sites-backend@0.1.2 + - @backstage/plugin-badges-backend@0.1.34 + - @backstage/plugin-graphql-backend@0.1.30 + - @backstage/plugin-jenkins-backend@0.1.30 + - @backstage/plugin-kafka-backend@0.2.33 + - @backstage/plugin-permission-backend@0.5.15 + - @backstage/plugin-permission-common@0.7.3 + - @backstage/plugin-permission-node@0.7.3 + - @backstage/plugin-playlist-backend@0.2.3 + - @backstage/plugin-proxy-backend@0.2.34 + - @backstage/plugin-rollbar-backend@0.1.37 + - @backstage/plugin-search-backend-module-pg@0.5.1 + - @backstage/plugin-search-common@1.2.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.24 + - @backstage/plugin-tech-insights-node@0.3.8 + - @backstage/plugin-techdocs-backend@1.5.1 + - @backstage/plugin-todo-backend@0.1.37 + +## 0.2.79-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-adr-backend@0.2.5-next.2 + - @backstage/backend-common@0.18.0-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.8-next.2 + - @backstage/plugin-scaffolder-backend@1.10.0-next.2 + - @backstage/backend-tasks@0.4.1-next.1 + - @backstage/catalog-client@1.3.0-next.2 + - @backstage/plugin-catalog-backend@1.7.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.1-next.2 + - @backstage/plugin-events-backend@0.2.1-next.1 + - @backstage/plugin-app-backend@0.3.40-next.1 + - @backstage/plugin-kubernetes-backend@0.9.1-next.2 + - @backstage/plugin-catalog-node@1.3.1-next.2 + - @backstage/plugin-events-node@0.2.1-next.1 + - @backstage/plugin-auth-backend@0.17.3-next.2 + - @backstage/plugin-auth-node@0.2.9-next.1 + - @backstage/plugin-permission-node@0.7.3-next.1 + - @backstage/plugin-playlist-backend@0.2.3-next.2 + - @backstage/plugin-rollbar-backend@0.1.37-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.1-next.2 + - @backstage/plugin-tech-insights-backend@0.5.6-next.2 + - @backstage/plugin-techdocs-backend@1.5.1-next.2 + - example-app@0.2.79-next.2 + - @backstage/plugin-azure-devops-backend@0.3.19-next.1 + - @backstage/plugin-azure-sites-backend@0.1.2-next.1 + - @backstage/plugin-badges-backend@0.1.34-next.2 + - @backstage/plugin-code-coverage-backend@0.2.6-next.2 + - @backstage/plugin-explore-backend@0.0.2-next.2 + - @backstage/plugin-graphql-backend@0.1.30-next.2 + - @backstage/plugin-jenkins-backend@0.1.30-next.2 + - @backstage/plugin-kafka-backend@0.2.33-next.2 + - @backstage/plugin-permission-backend@0.5.15-next.1 + - @backstage/plugin-proxy-backend@0.2.34-next.1 + - @backstage/plugin-search-backend@1.2.1-next.2 + - @backstage/plugin-search-backend-node@1.1.1-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.24-next.1 + - @backstage/plugin-tech-insights-node@0.3.8-next.1 + - @backstage/plugin-todo-backend@0.1.37-next.2 + - @backstage/catalog-model@1.1.5-next.1 + - @backstage/config@1.0.6-next.0 + - @backstage/integration@1.4.2-next.0 + - @backstage/plugin-permission-common@0.7.3-next.0 + - @backstage/plugin-search-common@1.2.1-next.0 + +## 0.2.79-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.10.0-next.1 + - @backstage/backend-common@0.18.0-next.0 + - @backstage/plugin-explore-backend@0.0.2-next.1 + - @backstage/plugin-events-backend@0.2.1-next.0 + - @backstage/plugin-app-backend@0.3.40-next.0 + - @backstage/plugin-tech-insights-backend@0.5.6-next.1 + - @backstage/config@1.0.6-next.0 + - @backstage/plugin-catalog-backend@1.7.0-next.1 + - @backstage/plugin-catalog-node@1.3.1-next.1 + - @backstage/plugin-events-node@0.2.1-next.0 + - example-app@0.2.79-next.1 + - @backstage/backend-tasks@0.4.1-next.0 + - @backstage/catalog-client@1.3.0-next.1 + - @backstage/catalog-model@1.1.5-next.1 + - @backstage/integration@1.4.2-next.0 + - @backstage/plugin-auth-backend@0.17.3-next.1 + - @backstage/plugin-auth-node@0.2.9-next.0 + - @backstage/plugin-azure-devops-backend@0.3.19-next.0 + - @backstage/plugin-azure-sites-backend@0.1.2-next.0 + - @backstage/plugin-badges-backend@0.1.34-next.1 + - @backstage/plugin-code-coverage-backend@0.2.6-next.1 + - @backstage/plugin-graphql-backend@0.1.30-next.1 + - @backstage/plugin-jenkins-backend@0.1.30-next.1 + - @backstage/plugin-kafka-backend@0.2.33-next.1 + - @backstage/plugin-kubernetes-backend@0.9.1-next.1 + - @backstage/plugin-permission-backend@0.5.15-next.0 + - @backstage/plugin-permission-common@0.7.3-next.0 + - @backstage/plugin-permission-node@0.7.3-next.0 + - @backstage/plugin-playlist-backend@0.2.3-next.1 + - @backstage/plugin-proxy-backend@0.2.34-next.0 + - @backstage/plugin-rollbar-backend@0.1.37-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.8-next.1 + - @backstage/plugin-search-backend@1.2.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.1-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.1-next.1 + - @backstage/plugin-search-backend-node@1.1.1-next.1 + - @backstage/plugin-search-common@1.2.1-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.24-next.0 + - @backstage/plugin-tech-insights-node@0.3.8-next.0 + - @backstage/plugin-techdocs-backend@1.5.1-next.1 + - @backstage/plugin-todo-backend@0.1.37-next.1 + +## 0.2.79-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.5-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.1-next.0 + - @backstage/plugin-search-backend-node@1.1.1-next.0 + - @backstage/catalog-client@1.3.0-next.0 + - @backstage/plugin-explore-backend@0.0.2-next.0 + - @backstage/plugin-code-coverage-backend@0.2.6-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.8-next.0 + - @backstage/plugin-scaffolder-backend@1.9.1-next.0 + - @backstage/plugin-catalog-backend@1.7.0-next.0 + - @backstage/plugin-search-backend@1.2.1-next.0 + - example-app@0.2.79-next.0 + - @backstage/backend-common@0.17.0 + - @backstage/backend-tasks@0.4.0 + - @backstage/config@1.0.5 + - @backstage/integration@1.4.1 + - @backstage/plugin-app-backend@0.3.39 + - @backstage/plugin-auth-backend@0.17.3-next.0 + - @backstage/plugin-auth-node@0.2.8 + - @backstage/plugin-azure-devops-backend@0.3.18 + - @backstage/plugin-azure-sites-backend@0.1.1 + - @backstage/plugin-badges-backend@0.1.34-next.0 + - @backstage/plugin-catalog-node@1.3.1-next.0 + - @backstage/plugin-events-backend@0.2.0 + - @backstage/plugin-events-node@0.2.0 + - @backstage/plugin-graphql-backend@0.1.30-next.0 + - @backstage/plugin-jenkins-backend@0.1.30-next.0 + - @backstage/plugin-kafka-backend@0.2.33-next.0 + - @backstage/plugin-kubernetes-backend@0.9.1-next.0 + - @backstage/plugin-permission-backend@0.5.14 + - @backstage/plugin-permission-common@0.7.2 + - @backstage/plugin-permission-node@0.7.2 + - @backstage/plugin-playlist-backend@0.2.3-next.0 + - @backstage/plugin-proxy-backend@0.2.33 + - @backstage/plugin-rollbar-backend@0.1.36 + - @backstage/plugin-search-backend-module-pg@0.5.1-next.0 + - @backstage/plugin-search-common@1.2.0 + - @backstage/plugin-tech-insights-backend@0.5.6-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23 + - @backstage/plugin-tech-insights-node@0.3.7 + - @backstage/plugin-techdocs-backend@1.5.1-next.0 + - @backstage/plugin-todo-backend@0.1.37-next.0 + +## 0.2.78 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.9.0 + - @backstage/plugin-azure-devops-backend@0.3.18 + - @backstage/plugin-kubernetes-backend@0.9.0 + - @backstage/plugin-catalog-backend@1.6.0 + - @backstage/catalog-client@1.2.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.7 + - @backstage/plugin-search-backend@1.2.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.0 + - @backstage/plugin-search-backend-node@1.1.0 + - @backstage/plugin-playlist-backend@0.2.2 + - @backstage/plugin-search-backend-module-pg@0.5.0 + - @backstage/backend-common@0.17.0 + - @backstage/plugin-app-backend@0.3.39 + - @backstage/plugin-catalog-node@1.3.0 + - @backstage/plugin-events-backend@0.2.0 + - @backstage/backend-tasks@0.4.0 + - @backstage/plugin-permission-backend@0.5.14 + - @backstage/plugin-permission-common@0.7.2 + - @backstage/plugin-permission-node@0.7.2 + - @backstage/plugin-kafka-backend@0.2.32 + - @backstage/plugin-jenkins-backend@0.1.29 + - @backstage/plugin-events-node@0.2.0 + - @backstage/integration@1.4.1 + - @backstage/plugin-auth-backend@0.17.2 + - @backstage/plugin-auth-node@0.2.8 + - @backstage/plugin-azure-sites-backend@0.1.1 + - @backstage/plugin-code-coverage-backend@0.2.5 + - @backstage/plugin-graphql-backend@0.1.29 + - @backstage/plugin-proxy-backend@0.2.33 + - @backstage/plugin-rollbar-backend@0.1.36 + - @backstage/plugin-techdocs-backend@1.5.0 + - @backstage/plugin-todo-backend@0.1.36 + - @backstage/plugin-explore-backend@0.0.1 + - @backstage/plugin-search-common@1.2.0 + - example-app@0.2.78 + - @backstage/plugin-badges-backend@0.1.33 + - @backstage/plugin-tech-insights-backend@0.5.5 + - @backstage/catalog-model@1.1.4 + - @backstage/config@1.0.5 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23 + - @backstage/plugin-tech-insights-node@0.3.7 + +## 0.2.78-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.6.0-next.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.3 + - @backstage/plugin-scaffolder-backend@1.9.0-next.3 + - @backstage/backend-tasks@0.4.0-next.3 + - @backstage/plugin-permission-backend@0.5.14-next.3 + - @backstage/plugin-permission-common@0.7.2-next.2 + - @backstage/plugin-permission-node@0.7.2-next.3 + - @backstage/plugin-playlist-backend@0.2.2-next.4 + - @backstage/plugin-search-backend@1.2.0-next.3 + - @backstage/plugin-kubernetes-backend@0.8.1-next.4 + - @backstage/backend-common@0.17.0-next.3 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.0-next.3 + - @backstage/plugin-techdocs-backend@1.5.0-next.3 + - example-app@0.2.78-next.4 + - @backstage/catalog-client@1.2.0-next.1 + - @backstage/catalog-model@1.1.4-next.1 + - @backstage/config@1.0.5-next.1 + - @backstage/integration@1.4.1-next.1 + - @backstage/plugin-app-backend@0.3.39-next.3 + - @backstage/plugin-auth-backend@0.17.2-next.3 + - @backstage/plugin-auth-node@0.2.8-next.3 + - @backstage/plugin-azure-devops-backend@0.3.18-next.3 + - @backstage/plugin-azure-sites-backend@0.1.1-next.3 + - @backstage/plugin-badges-backend@0.1.33-next.3 + - @backstage/plugin-catalog-node@1.3.0-next.3 + - @backstage/plugin-code-coverage-backend@0.2.5-next.3 + - @backstage/plugin-events-backend@0.2.0-next.3 + - @backstage/plugin-events-node@0.2.0-next.3 + - @backstage/plugin-explore-backend@0.0.1-next.2 + - @backstage/plugin-graphql-backend@0.1.29-next.3 + - @backstage/plugin-jenkins-backend@0.1.29-next.3 + - @backstage/plugin-kafka-backend@0.2.32-next.3 + - @backstage/plugin-proxy-backend@0.2.33-next.3 + - @backstage/plugin-rollbar-backend@0.1.36-next.3 + - @backstage/plugin-search-backend-module-pg@0.4.3-next.3 + - @backstage/plugin-search-backend-node@1.1.0-next.3 + - @backstage/plugin-search-common@1.2.0-next.3 + - @backstage/plugin-tech-insights-backend@0.5.5-next.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.3 + - @backstage/plugin-tech-insights-node@0.3.7-next.3 + - @backstage/plugin-todo-backend@0.1.36-next.3 + +## 0.2.78-next.3 + +### Patch Changes + +- Updated dependencies + - example-app@0.2.78-next.3 + - @backstage/backend-common@0.17.0-next.2 + - @backstage/backend-tasks@0.4.0-next.2 + - @backstage/catalog-client@1.2.0-next.1 + - @backstage/catalog-model@1.1.4-next.1 + - @backstage/config@1.0.5-next.1 + - @backstage/integration@1.4.1-next.1 + - @backstage/plugin-app-backend@0.3.39-next.2 + - @backstage/plugin-auth-backend@0.17.2-next.2 + - @backstage/plugin-auth-node@0.2.8-next.2 + - @backstage/plugin-azure-devops-backend@0.3.18-next.2 + - @backstage/plugin-azure-sites-backend@0.1.1-next.2 + - @backstage/plugin-badges-backend@0.1.33-next.2 + - @backstage/plugin-catalog-backend@1.6.0-next.2 + - @backstage/plugin-catalog-node@1.3.0-next.2 + - @backstage/plugin-code-coverage-backend@0.2.5-next.2 + - @backstage/plugin-events-backend@0.2.0-next.2 + - @backstage/plugin-events-node@0.2.0-next.2 + - @backstage/plugin-explore-backend@0.0.1-next.1 + - @backstage/plugin-graphql-backend@0.1.29-next.2 + - @backstage/plugin-jenkins-backend@0.1.29-next.2 + - @backstage/plugin-kafka-backend@0.2.32-next.2 + - @backstage/plugin-kubernetes-backend@0.8.1-next.3 + - @backstage/plugin-permission-backend@0.5.14-next.2 + - @backstage/plugin-permission-common@0.7.2-next.1 + - @backstage/plugin-permission-node@0.7.2-next.2 + - @backstage/plugin-playlist-backend@0.2.2-next.3 + - @backstage/plugin-proxy-backend@0.2.33-next.2 + - @backstage/plugin-rollbar-backend@0.1.36-next.2 + - @backstage/plugin-scaffolder-backend@1.9.0-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.2 + - @backstage/plugin-search-backend@1.2.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.0-next.2 + - @backstage/plugin-search-backend-module-pg@0.4.3-next.2 + - @backstage/plugin-search-backend-node@1.1.0-next.2 + - @backstage/plugin-search-common@1.2.0-next.2 + - @backstage/plugin-tech-insights-backend@0.5.5-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.2 + - @backstage/plugin-tech-insights-node@0.3.7-next.2 + - @backstage/plugin-techdocs-backend@1.4.2-next.2 + - @backstage/plugin-todo-backend@0.1.36-next.2 + +## 0.2.78-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-azure-devops-backend@0.3.18-next.2 + - @backstage/plugin-search-backend@1.2.0-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.1.0-next.2 + - @backstage/plugin-catalog-backend@1.6.0-next.2 + - @backstage/plugin-playlist-backend@0.2.2-next.2 + - @backstage/plugin-search-backend-module-pg@0.4.3-next.2 + - @backstage/plugin-app-backend@0.3.39-next.2 + - @backstage/plugin-catalog-node@1.3.0-next.2 + - @backstage/plugin-events-backend@0.2.0-next.2 + - @backstage/plugin-scaffolder-backend@1.9.0-next.2 + - @backstage/backend-common@0.17.0-next.2 + - @backstage/plugin-search-common@1.2.0-next.2 + - example-app@0.2.78-next.2 + - @backstage/plugin-techdocs-backend@1.4.2-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.2 + - @backstage/backend-tasks@0.4.0-next.2 + - @backstage/plugin-auth-backend@0.17.2-next.2 + - @backstage/plugin-auth-node@0.2.8-next.2 + - @backstage/plugin-azure-sites-backend@0.1.1-next.2 + - @backstage/plugin-badges-backend@0.1.33-next.2 + - @backstage/plugin-code-coverage-backend@0.2.5-next.2 + - @backstage/plugin-explore-backend@0.0.1-next.1 + - @backstage/plugin-graphql-backend@0.1.29-next.2 + - @backstage/plugin-jenkins-backend@0.1.29-next.2 + - @backstage/plugin-kafka-backend@0.2.32-next.2 + - @backstage/plugin-kubernetes-backend@0.8.1-next.2 + - @backstage/plugin-permission-backend@0.5.14-next.2 + - @backstage/plugin-permission-node@0.7.2-next.2 + - @backstage/plugin-proxy-backend@0.2.33-next.2 + - @backstage/plugin-rollbar-backend@0.1.36-next.2 + - @backstage/plugin-tech-insights-backend@0.5.5-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.2 + - @backstage/plugin-tech-insights-node@0.3.7-next.2 + - @backstage/plugin-todo-backend@0.1.36-next.2 + - @backstage/catalog-client@1.2.0-next.1 + - @backstage/catalog-model@1.1.4-next.1 + - @backstage/config@1.0.5-next.1 + - @backstage/integration@1.4.1-next.1 + - @backstage/plugin-events-node@0.2.0-next.2 + - @backstage/plugin-permission-common@0.7.2-next.1 + +## 0.2.78-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.17.0-next.1 + - @backstage/plugin-catalog-backend@1.6.0-next.1 + - @backstage/plugin-kafka-backend@0.2.32-next.1 + - @backstage/backend-tasks@0.4.0-next.1 + - @backstage/plugin-search-backend-node@1.0.5-next.1 + - @backstage/plugin-jenkins-backend@0.1.29-next.1 + - @backstage/plugin-scaffolder-backend@1.8.1-next.1 + - @backstage/plugin-explore-backend@0.0.1-next.0 + - @backstage/plugin-proxy-backend@0.2.33-next.1 + - @backstage/plugin-app-backend@0.3.39-next.1 + - @backstage/plugin-auth-backend@0.17.2-next.1 + - @backstage/plugin-auth-node@0.2.8-next.1 + - @backstage/plugin-azure-devops-backend@0.3.18-next.1 + - @backstage/plugin-azure-sites-backend@0.1.1-next.1 + - @backstage/plugin-badges-backend@0.1.33-next.1 + - @backstage/plugin-catalog-node@1.2.2-next.1 + - @backstage/plugin-code-coverage-backend@0.2.5-next.1 + - @backstage/plugin-events-backend@0.2.0-next.1 + - @backstage/plugin-graphql-backend@0.1.29-next.1 + - @backstage/plugin-kubernetes-backend@0.8.1-next.1 + - @backstage/plugin-permission-backend@0.5.14-next.1 + - @backstage/plugin-permission-node@0.7.2-next.1 + - @backstage/plugin-playlist-backend@0.2.2-next.1 + - @backstage/plugin-rollbar-backend@0.1.36-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.1 + - @backstage/plugin-search-backend@1.1.2-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.5-next.1 + - @backstage/plugin-search-backend-module-pg@0.4.3-next.1 + - @backstage/plugin-tech-insights-backend@0.5.5-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.1 + - @backstage/plugin-tech-insights-node@0.3.7-next.1 + - @backstage/plugin-techdocs-backend@1.4.2-next.1 + - @backstage/plugin-todo-backend@0.1.36-next.1 + - example-app@0.2.78-next.1 + - @backstage/config@1.0.5-next.1 + - @backstage/integration@1.4.1-next.1 + - @backstage/catalog-client@1.2.0-next.1 + - @backstage/catalog-model@1.1.4-next.1 + - @backstage/plugin-events-node@0.2.0-next.1 + - @backstage/plugin-permission-common@0.7.2-next.1 + - @backstage/plugin-search-common@1.1.2-next.1 + +## 0.2.78-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.1-next.0 + - @backstage/catalog-client@1.2.0-next.0 + - @backstage/plugin-catalog-backend@1.6.0-next.0 + - @backstage/plugin-events-backend@0.2.0-next.0 + - @backstage/plugin-search-backend-node@1.0.5-next.0 + - @backstage/plugin-events-node@0.2.0-next.0 + - @backstage/backend-common@0.16.1-next.0 + - @backstage/integration@1.4.1-next.0 + - @backstage/plugin-app-backend@0.3.39-next.0 + - @backstage/plugin-auth-backend@0.17.2-next.0 + - @backstage/plugin-auth-node@0.2.8-next.0 + - @backstage/plugin-azure-devops-backend@0.3.18-next.0 + - @backstage/plugin-azure-sites-backend@0.1.1-next.0 + - @backstage/plugin-code-coverage-backend@0.2.5-next.0 + - @backstage/plugin-graphql-backend@0.1.29-next.0 + - @backstage/plugin-jenkins-backend@0.1.29-next.0 + - @backstage/plugin-permission-backend@0.5.14-next.0 + - @backstage/plugin-permission-common@0.7.2-next.0 + - @backstage/plugin-permission-node@0.7.2-next.0 + - @backstage/plugin-playlist-backend@0.2.2-next.0 + - @backstage/plugin-proxy-backend@0.2.33-next.0 + - @backstage/plugin-rollbar-backend@0.1.36-next.0 + - @backstage/plugin-techdocs-backend@1.4.2-next.0 + - @backstage/plugin-todo-backend@0.1.36-next.0 + - @backstage/plugin-kubernetes-backend@0.8.1-next.0 + - example-app@0.2.78-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.0 + - @backstage/plugin-badges-backend@0.1.33-next.0 + - @backstage/plugin-catalog-node@1.2.2-next.0 + - @backstage/plugin-tech-insights-backend@0.5.5-next.0 + - @backstage/backend-tasks@0.3.8-next.0 + - @backstage/catalog-model@1.1.4-next.0 + - @backstage/config@1.0.5-next.0 + - @backstage/plugin-kafka-backend@0.2.32-next.0 + - @backstage/plugin-search-backend@1.1.2-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.5-next.0 + - @backstage/plugin-search-backend-module-pg@0.4.3-next.0 + - @backstage/plugin-search-common@1.1.2-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.0 + - @backstage/plugin-tech-insights-node@0.3.7-next.0 + +## 0.2.77 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-backend@0.17.1 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/plugin-techdocs-backend@1.4.1 + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/plugin-playlist-backend@0.2.1 + - @backstage/plugin-azure-devops-backend@0.3.17 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-code-coverage-backend@0.2.4 + - @backstage/plugin-events-backend@0.1.0 + - @backstage/plugin-events-node@0.1.0 + - @backstage/plugin-kubernetes-backend@0.8.0 + - @backstage/plugin-tech-insights-backend@0.5.4 + - @backstage/plugin-tech-insights-node@0.3.6 + - @backstage/plugin-azure-sites-backend@0.1.0 + - example-app@0.2.77 + - @backstage/plugin-app-backend@0.3.38 + - @backstage/plugin-badges-backend@0.1.32 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/plugin-graphql-backend@0.1.28 + - @backstage/plugin-jenkins-backend@0.1.28 + - @backstage/plugin-kafka-backend@0.2.31 + - @backstage/plugin-permission-backend@0.5.13 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/plugin-proxy-backend@0.2.32 + - @backstage/plugin-rollbar-backend@0.1.35 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.6 + - @backstage/plugin-search-backend@1.1.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.4 + - @backstage/plugin-search-backend-module-pg@0.4.2 + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22 + - @backstage/plugin-todo-backend@0.1.35 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## 0.2.77-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.17.1-next.1 + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/plugin-code-coverage-backend@0.2.4-next.1 + - @backstage/plugin-kubernetes-backend@0.8.0-next.1 + - @backstage/plugin-tech-insights-backend@0.5.4-next.1 + - example-app@0.2.77-next.2 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-app-backend@0.3.38-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-azure-devops-backend@0.3.17-next.2 + - @backstage/plugin-azure-sites-backend@0.1.0-next.1 + - @backstage/plugin-badges-backend@0.1.32-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-graphql-backend@0.1.28-next.1 + - @backstage/plugin-jenkins-backend@0.1.28-next.1 + - @backstage/plugin-kafka-backend@0.2.31-next.1 + - @backstage/plugin-permission-backend@0.5.13-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/plugin-playlist-backend@0.2.1-next.2 + - @backstage/plugin-proxy-backend@0.2.32-next.1 + - @backstage/plugin-rollbar-backend@0.1.35-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.2 + - @backstage/plugin-search-backend@1.1.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.4.2-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/plugin-techdocs-backend@1.4.1-next.1 + - @backstage/plugin-todo-backend@0.1.35-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## 0.2.77-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0-next.1 + - @backstage/plugin-playlist-backend@0.2.1-next.1 + - @backstage/plugin-azure-devops-backend@0.3.17-next.1 + - example-app@0.2.77-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.1 + +## 0.2.77-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.0 + - @backstage/plugin-catalog-backend@1.5.1-next.0 + - @backstage/plugin-techdocs-backend@1.4.1-next.0 + - @backstage/plugin-scaffolder-backend@1.8.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-auth-backend@0.17.1-next.0 + - @backstage/backend-tasks@0.3.7-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/plugin-auth-node@0.2.7-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-tech-insights-backend@0.5.4-next.0 + - @backstage/plugin-tech-insights-node@0.3.6-next.0 + - @backstage/plugin-azure-sites-backend@0.1.0-next.0 + - @backstage/plugin-kubernetes-backend@0.8.0-next.0 + - example-app@0.2.77-next.0 + - @backstage/plugin-app-backend@0.3.38-next.0 + - @backstage/plugin-azure-devops-backend@0.3.17-next.0 + - @backstage/plugin-badges-backend@0.1.32-next.0 + - @backstage/plugin-code-coverage-backend@0.2.4-next.0 + - @backstage/plugin-graphql-backend@0.1.28-next.0 + - @backstage/plugin-jenkins-backend@0.1.28-next.0 + - @backstage/plugin-kafka-backend@0.2.31-next.0 + - @backstage/plugin-permission-backend@0.5.13-next.0 + - @backstage/plugin-permission-node@0.7.1-next.0 + - @backstage/plugin-playlist-backend@0.2.1-next.0 + - @backstage/plugin-proxy-backend@0.2.32-next.0 + - @backstage/plugin-rollbar-backend@0.1.35-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.0 + - @backstage/plugin-search-backend@1.1.1-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.0 + - @backstage/plugin-search-backend-module-pg@0.4.2-next.0 + - @backstage/plugin-search-backend-node@1.0.4-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.0 + - @backstage/plugin-todo-backend@0.1.35-next.0 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## 0.2.76 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.2 + - @backstage/backend-common@0.15.2 + - @backstage/plugin-catalog-backend@1.5.0 + - @backstage/plugin-scaffolder-backend@1.7.0 + - @backstage/plugin-auth-node@0.2.6 + - @backstage/backend-tasks@0.3.6 + - @backstage/plugin-permission-node@0.7.0 + - @backstage/plugin-auth-backend@0.17.0 + - @backstage/plugin-permission-common@0.7.0 + - @backstage/plugin-tech-insights-backend@0.5.3 + - @backstage/plugin-search-backend@1.1.0 + - @backstage/catalog-client@1.1.1 + - @backstage/plugin-playlist-backend@0.2.0 + - @backstage/plugin-jenkins-backend@0.1.27 + - @backstage/plugin-app-backend@0.3.37 + - @backstage/plugin-badges-backend@0.1.31 + - @backstage/plugin-graphql-backend@0.1.27 + - @backstage/plugin-permission-backend@0.5.12 + - @backstage/plugin-rollbar-backend@0.1.34 + - @backstage/plugin-kubernetes-backend@0.7.3 + - @backstage/plugin-search-common@1.1.0 + - @backstage/plugin-search-backend-node@1.0.3 + - @backstage/plugin-search-backend-module-pg@0.4.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.3 + - @backstage/plugin-techdocs-backend@1.4.0 + - @backstage/plugin-tech-insights-node@0.3.5 + - example-app@0.2.76 + - @backstage/plugin-code-coverage-backend@0.2.3 + - @backstage/plugin-kafka-backend@0.2.30 + - @backstage/plugin-todo-backend@0.1.34 + - @backstage/plugin-azure-devops-backend@0.3.16 + - @backstage/plugin-proxy-backend@0.2.31 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.5 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21 + - @backstage/config@1.0.3 + - @backstage/integration@1.3.2 + +## 0.2.76-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.5.0-next.2 + - @backstage/backend-tasks@0.3.6-next.2 + - @backstage/backend-common@0.15.2-next.2 + - @backstage/plugin-permission-common@0.7.0-next.2 + - @backstage/plugin-permission-node@0.7.0-next.2 + - @backstage/plugin-scaffolder-backend@1.7.0-next.2 + - @backstage/plugin-playlist-backend@0.2.0-next.2 + - @backstage/plugin-badges-backend@0.1.31-next.2 + - @backstage/plugin-graphql-backend@0.1.27-next.2 + - @backstage/plugin-permission-backend@0.5.12-next.2 + - @backstage/plugin-rollbar-backend@0.1.34-next.2 + - @backstage/plugin-search-backend@1.1.0-next.2 + - @backstage/plugin-tech-insights-backend@0.5.3-next.2 + - @backstage/plugin-techdocs-backend@1.4.0-next.2 + - example-app@0.2.76-next.2 + - @backstage/plugin-search-backend-node@1.0.3-next.2 + - @backstage/plugin-tech-insights-node@0.3.5-next.2 + - @backstage/plugin-app-backend@0.3.37-next.2 + - @backstage/plugin-auth-backend@0.17.0-next.2 + - @backstage/plugin-auth-node@0.2.6-next.2 + - @backstage/plugin-azure-devops-backend@0.3.16-next.2 + - @backstage/plugin-code-coverage-backend@0.2.3-next.2 + - @backstage/plugin-jenkins-backend@0.1.27-next.2 + - @backstage/plugin-kafka-backend@0.2.30-next.2 + - @backstage/plugin-kubernetes-backend@0.7.3-next.2 + - @backstage/plugin-proxy-backend@0.2.31-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.2 + - @backstage/plugin-search-backend-module-pg@0.4.1-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.2 + - @backstage/plugin-todo-backend@0.1.34-next.2 + - @backstage/plugin-search-common@1.1.0-next.2 + - @backstage/catalog-client@1.1.1-next.2 + - @backstage/catalog-model@1.1.2-next.2 + - @backstage/config@1.0.3-next.2 + - @backstage/integration@1.3.2-next.2 + +## 0.2.76-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.17.0-next.1 + - @backstage/plugin-search-backend@1.1.0-next.1 + - @backstage/catalog-client@1.1.1-next.1 + - @backstage/backend-common@0.15.2-next.1 + - @backstage/plugin-scaffolder-backend@1.7.0-next.1 + - @backstage/plugin-search-common@1.1.0-next.1 + - @backstage/plugin-search-backend-node@1.0.3-next.1 + - @backstage/plugin-search-backend-module-pg@0.4.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.1 + - @backstage/plugin-kubernetes-backend@0.7.3-next.1 + - @backstage/plugin-tech-insights-backend@0.5.3-next.1 + - example-app@0.2.76-next.1 + - @backstage/backend-tasks@0.3.6-next.1 + - @backstage/catalog-model@1.1.2-next.1 + - @backstage/config@1.0.3-next.1 + - @backstage/integration@1.3.2-next.1 + - @backstage/plugin-app-backend@0.3.37-next.1 + - @backstage/plugin-auth-node@0.2.6-next.1 + - @backstage/plugin-azure-devops-backend@0.3.16-next.1 + - @backstage/plugin-badges-backend@0.1.31-next.1 + - @backstage/plugin-catalog-backend@1.4.1-next.1 + - @backstage/plugin-code-coverage-backend@0.2.3-next.1 + - @backstage/plugin-graphql-backend@0.1.27-next.1 + - @backstage/plugin-jenkins-backend@0.1.27-next.1 + - @backstage/plugin-kafka-backend@0.2.30-next.1 + - @backstage/plugin-permission-backend@0.5.12-next.1 + - @backstage/plugin-permission-common@0.6.5-next.1 + - @backstage/plugin-permission-node@0.6.6-next.1 + - @backstage/plugin-playlist-backend@0.1.1-next.1 + - @backstage/plugin-proxy-backend@0.2.31-next.1 + - @backstage/plugin-rollbar-backend@0.1.34-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.1 + - @backstage/plugin-tech-insights-node@0.3.5-next.1 + - @backstage/plugin-techdocs-backend@1.3.1-next.1 + - @backstage/plugin-todo-backend@0.1.34-next.1 + +## 0.2.76-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.2-next.0 + - @backstage/plugin-scaffolder-backend@1.7.0-next.0 + - @backstage/plugin-auth-backend@0.17.0-next.0 + - @backstage/plugin-catalog-backend@1.4.1-next.0 + - @backstage/plugin-jenkins-backend@0.1.27-next.0 + - @backstage/plugin-app-backend@0.3.37-next.0 + - @backstage/plugin-tech-insights-node@0.3.5-next.0 + - example-app@0.2.76-next.0 + - @backstage/catalog-client@1.1.1-next.0 + - @backstage/plugin-badges-backend@0.1.31-next.0 + - @backstage/plugin-code-coverage-backend@0.2.3-next.0 + - @backstage/plugin-kafka-backend@0.2.30-next.0 + - @backstage/plugin-kubernetes-backend@0.7.3-next.0 + - @backstage/plugin-playlist-backend@0.1.1-next.0 + - @backstage/plugin-tech-insights-backend@0.5.3-next.0 + - @backstage/plugin-techdocs-backend@1.3.1-next.0 + - @backstage/plugin-todo-backend@0.1.34-next.0 + - @backstage/backend-common@0.15.2-next.0 + - @backstage/backend-tasks@0.3.6-next.0 + - @backstage/plugin-auth-node@0.2.6-next.0 + - @backstage/plugin-permission-node@0.6.6-next.0 + - @backstage/plugin-rollbar-backend@0.1.34-next.0 + - @backstage/plugin-search-backend-module-pg@0.4.1-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.0 + - @backstage/config@1.0.3-next.0 + - @backstage/integration@1.3.2-next.0 + - @backstage/plugin-azure-devops-backend@0.3.16-next.0 + - @backstage/plugin-graphql-backend@0.1.27-next.0 + - @backstage/plugin-permission-backend@0.5.12-next.0 + - @backstage/plugin-permission-common@0.6.5-next.0 + - @backstage/plugin-proxy-backend@0.2.31-next.0 + - @backstage/plugin-search-backend@1.0.3-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.0 + - @backstage/plugin-search-backend-node@1.0.3-next.0 + - @backstage/plugin-search-common@1.0.2-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.0 + +## 0.2.75 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/plugin-kubernetes-backend@0.7.2 + - @backstage/plugin-kafka-backend@0.2.29 + - @backstage/plugin-proxy-backend@0.2.30 + - @backstage/plugin-auth-backend@0.16.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/plugin-azure-devops-backend@0.3.15 + - @backstage/plugin-search-backend-node@1.0.2 + - @backstage/plugin-tech-insights-node@0.3.4 + - @backstage/backend-tasks@0.3.5 + - @backstage/plugin-techdocs-backend@1.3.0 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.4 + - @backstage/plugin-search-backend-module-pg@0.4.0 + - @backstage/plugin-jenkins-backend@0.1.26 + - @backstage/plugin-playlist-backend@0.1.0 + - @backstage/plugin-app-backend@0.3.36 + - @backstage/plugin-graphql-backend@0.1.26 + - @backstage/plugin-rollbar-backend@0.1.33 + - @backstage/plugin-code-coverage-backend@0.2.2 + - @backstage/plugin-permission-backend@0.5.11 + - @backstage/plugin-todo-backend@0.1.33 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.2 + - @backstage/plugin-tech-insights-backend@0.5.2 + - @backstage/plugin-badges-backend@0.1.30 + - example-app@0.2.75 + - @backstage/plugin-search-backend@1.0.2 + - @backstage/plugin-search-common@1.0.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20 + +## 0.2.75-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.1.0-next.2 + - @backstage/catalog-model@1.1.1-next.0 + - @backstage/config@1.0.2-next.0 + - @backstage/integration@1.3.1-next.2 + - @backstage/plugin-permission-common@0.6.4-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.4-next.1 + - @backstage/plugin-catalog-backend@1.4.0-next.3 + - @backstage/plugin-auth-backend@0.16.0-next.3 + - @backstage/backend-common@0.15.1-next.3 + - @backstage/plugin-scaffolder-backend@1.6.0-next.3 + - @backstage/plugin-badges-backend@0.1.30-next.1 + - @backstage/plugin-code-coverage-backend@0.2.2-next.2 + - @backstage/plugin-jenkins-backend@0.1.26-next.3 + - @backstage/plugin-kubernetes-backend@0.7.2-next.3 + - @backstage/plugin-tech-insights-backend@0.5.2-next.2 + - @backstage/plugin-techdocs-backend@1.3.0-next.2 + - @backstage/plugin-todo-backend@0.1.33-next.2 + - example-app@0.2.75-next.3 + - @backstage/plugin-kafka-backend@0.2.29-next.1 + - @backstage/backend-tasks@0.3.5-next.1 + - @backstage/plugin-app-backend@0.3.36-next.3 + - @backstage/plugin-auth-node@0.2.5-next.3 + - @backstage/plugin-azure-devops-backend@0.3.15-next.2 + - @backstage/plugin-graphql-backend@0.1.26-next.3 + - @backstage/plugin-permission-backend@0.5.11-next.2 + - @backstage/plugin-permission-node@0.6.5-next.3 + - @backstage/plugin-proxy-backend@0.2.30-next.2 + - @backstage/plugin-rollbar-backend@0.1.33-next.3 + - @backstage/plugin-search-backend@1.0.2-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.2-next.2 + - @backstage/plugin-search-backend-module-pg@0.4.0-next.2 + - @backstage/plugin-search-backend-node@1.0.2-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20-next.1 + - @backstage/plugin-tech-insights-node@0.3.4-next.1 + +## 0.2.75-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.7.2-next.2 + - @backstage/backend-common@0.15.1-next.2 + - @backstage/integration@1.3.1-next.1 + - @backstage/plugin-catalog-backend@1.4.0-next.2 + - @backstage/plugin-scaffolder-backend@1.6.0-next.2 + - @backstage/plugin-auth-node@0.2.5-next.2 + - @backstage/plugin-techdocs-backend@1.3.0-next.1 + - @backstage/plugin-jenkins-backend@0.1.26-next.2 + - @backstage/catalog-client@1.0.5-next.1 + - @backstage/plugin-app-backend@0.3.36-next.2 + - @backstage/plugin-auth-backend@0.16.0-next.2 + - @backstage/plugin-azure-devops-backend@0.3.15-next.1 + - @backstage/plugin-code-coverage-backend@0.2.2-next.1 + - @backstage/plugin-graphql-backend@0.1.26-next.2 + - @backstage/plugin-permission-backend@0.5.11-next.1 + - @backstage/plugin-permission-common@0.6.4-next.1 + - @backstage/plugin-permission-node@0.6.5-next.2 + - @backstage/plugin-proxy-backend@0.2.30-next.1 + - @backstage/plugin-rollbar-backend@0.1.33-next.2 + - @backstage/plugin-todo-backend@0.1.33-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.2-next.1 + - example-app@0.2.75-next.2 + +## 0.2.75-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.2.5-next.1 + - @backstage/plugin-permission-node@0.6.5-next.1 + - @backstage/backend-common@0.15.1-next.1 + - @backstage/plugin-catalog-backend@1.4.0-next.1 + - @backstage/plugin-auth-backend@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.6.0-next.1 + - @backstage/plugin-search-backend-node@1.0.2-next.1 + - @backstage/plugin-app-backend@0.3.36-next.1 + - @backstage/plugin-graphql-backend@0.1.26-next.1 + - @backstage/plugin-jenkins-backend@0.1.26-next.1 + - @backstage/plugin-rollbar-backend@0.1.33-next.1 + - @backstage/plugin-search-backend-module-pg@0.4.0-next.1 + - @backstage/plugin-kubernetes-backend@0.7.2-next.1 + - @backstage/plugin-tech-insights-backend@0.5.2-next.1 + - example-app@0.2.75-next.1 + +## 0.2.75-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1-next.0 + - @backstage/plugin-scaffolder-backend@1.6.0-next.0 + - @backstage/plugin-kafka-backend@0.2.29-next.0 + - @backstage/plugin-proxy-backend@0.2.30-next.0 + - @backstage/plugin-azure-devops-backend@0.3.15-next.0 + - @backstage/plugin-search-backend-node@1.0.2-next.0 + - @backstage/plugin-tech-insights-node@0.3.4-next.0 + - @backstage/backend-tasks@0.3.5-next.0 + - @backstage/plugin-catalog-backend@1.3.2-next.0 + - @backstage/plugin-search-backend-module-pg@0.4.0-next.0 + - @backstage/catalog-client@1.0.5-next.0 + - @backstage/integration@1.3.1-next.0 + - @backstage/plugin-app-backend@0.3.36-next.0 + - @backstage/plugin-auth-backend@0.15.2-next.0 + - @backstage/plugin-auth-node@0.2.5-next.0 + - @backstage/plugin-code-coverage-backend@0.2.2-next.0 + - @backstage/plugin-graphql-backend@0.1.26-next.0 + - @backstage/plugin-jenkins-backend@0.1.26-next.0 + - @backstage/plugin-permission-backend@0.5.11-next.0 + - @backstage/plugin-permission-common@0.6.4-next.0 + - @backstage/plugin-permission-node@0.6.5-next.0 + - @backstage/plugin-rollbar-backend@0.1.33-next.0 + - @backstage/plugin-techdocs-backend@1.2.2-next.0 + - @backstage/plugin-todo-backend@0.1.33-next.0 + - @backstage/plugin-tech-insights-backend@0.5.2-next.0 + - @backstage/plugin-badges-backend@0.1.30-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.2-next.0 + - @backstage/plugin-kubernetes-backend@0.7.2-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.4-next.0 + - @backstage/plugin-search-backend@1.0.2-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20-next.0 + - example-app@0.2.75-next.0 + - @backstage/plugin-search-common@1.0.1-next.0 + +## 0.2.74 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0 + - @backstage/plugin-kubernetes-backend@0.7.1 + - @backstage/integration@1.3.0 + - @backstage/plugin-scaffolder-backend@1.5.0 + - @backstage/plugin-auth-backend@0.15.1 + - @backstage/plugin-graphql-backend@0.1.25 + - @backstage/backend-tasks@0.3.4 + - @backstage/plugin-tech-insights-node@0.3.3 + - @backstage/plugin-catalog-backend@1.3.1 + - example-app@0.2.74 + - @backstage/plugin-app-backend@0.3.35 + - @backstage/plugin-auth-node@0.2.4 + - @backstage/plugin-azure-devops-backend@0.3.14 + - @backstage/plugin-badges-backend@0.1.29 + - @backstage/plugin-code-coverage-backend@0.2.1 + - @backstage/plugin-jenkins-backend@0.1.25 + - @backstage/plugin-kafka-backend@0.2.28 + - @backstage/plugin-permission-backend@0.5.10 + - @backstage/plugin-permission-node@0.6.4 + - @backstage/plugin-proxy-backend@0.2.29 + - @backstage/plugin-rollbar-backend@0.1.32 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.3 + - @backstage/plugin-search-backend@1.0.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.1 + - @backstage/plugin-search-backend-module-pg@0.3.6 + - @backstage/plugin-search-backend-node@1.0.1 + - @backstage/plugin-tech-insights-backend@0.5.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.19 + - @backstage/plugin-techdocs-backend@1.2.1 + - @backstage/plugin-todo-backend@0.1.32 + +## 0.2.74-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.0 + - @backstage/integration@1.3.0-next.0 + - @backstage/plugin-scaffolder-backend@1.5.0-next.0 + - @backstage/backend-tasks@0.3.4-next.0 + - @backstage/plugin-kubernetes-backend@0.7.1-next.0 + - @backstage/plugin-tech-insights-node@0.3.3-next.0 + - @backstage/plugin-app-backend@0.3.35-next.0 + - @backstage/plugin-auth-backend@0.15.1-next.0 + - @backstage/plugin-auth-node@0.2.4-next.0 + - @backstage/plugin-azure-devops-backend@0.3.14-next.0 + - @backstage/plugin-badges-backend@0.1.29-next.0 + - @backstage/plugin-catalog-backend@1.3.1-next.0 + - @backstage/plugin-code-coverage-backend@0.2.1-next.0 + - @backstage/plugin-graphql-backend@0.1.25-next.0 + - @backstage/plugin-jenkins-backend@0.1.25-next.0 + - @backstage/plugin-kafka-backend@0.2.28-next.0 + - @backstage/plugin-permission-backend@0.5.10-next.0 + - @backstage/plugin-permission-node@0.6.4-next.0 + - @backstage/plugin-proxy-backend@0.2.29-next.0 + - @backstage/plugin-rollbar-backend@0.1.32-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.3-next.0 + - @backstage/plugin-search-backend@1.0.1-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.1-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.6-next.0 + - @backstage/plugin-search-backend-node@1.0.1-next.0 + - @backstage/plugin-tech-insights-backend@0.5.1-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.19-next.0 + - @backstage/plugin-techdocs-backend@1.2.1-next.0 + - @backstage/plugin-todo-backend@0.1.32-next.0 + - example-app@0.2.74-next.0 + +## 0.2.73 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-code-coverage-backend@0.2.0 + - @backstage/plugin-catalog-backend@1.3.0 + - @backstage/plugin-tech-insights-backend@0.5.0 + - @backstage/backend-common@0.14.1 + - @backstage/catalog-model@1.1.0 + - @backstage/plugin-kubernetes-backend@0.7.0 + - @backstage/plugin-search-backend@1.0.0 + - @backstage/plugin-search-backend-node@1.0.0 + - @backstage/plugin-search-common@1.0.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.0 + - @backstage/plugin-scaffolder-backend@1.4.0 + - @backstage/plugin-auth-backend@0.15.0 + - @backstage/plugin-jenkins-backend@0.1.24 + - @backstage/plugin-proxy-backend@0.2.28 + - @backstage/plugin-search-backend-module-pg@0.3.5 + - @backstage/integration@1.2.2 + - @backstage/catalog-client@1.0.4 + - @backstage/plugin-app-backend@0.3.34 + - @backstage/plugin-auth-node@0.2.3 + - @backstage/plugin-azure-devops-backend@0.3.13 + - @backstage/plugin-graphql-backend@0.1.24 + - @backstage/plugin-permission-backend@0.5.9 + - @backstage/plugin-permission-common@0.6.3 + - @backstage/plugin-permission-node@0.6.3 + - @backstage/plugin-rollbar-backend@0.1.31 + - @backstage/plugin-techdocs-backend@1.2.0 + - @backstage/plugin-todo-backend@0.1.31 + - @backstage/backend-tasks@0.3.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18 + - @backstage/plugin-tech-insights-node@0.3.2 + - @backstage/plugin-kafka-backend@0.2.27 + - @backstage/plugin-badges-backend@0.1.28 + - example-app@0.2.73 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.2 + +## 0.2.73-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-code-coverage-backend@0.2.0-next.3 + - @backstage/plugin-catalog-backend@1.3.0-next.3 + - @backstage/plugin-kubernetes-backend@0.7.0-next.3 + - @backstage/plugin-proxy-backend@0.2.28-next.1 + - @backstage/backend-common@0.14.1-next.3 + - @backstage/plugin-scaffolder-backend@1.4.0-next.3 + - @backstage/catalog-client@1.0.4-next.2 + - @backstage/integration@1.2.2-next.3 + - @backstage/plugin-app-backend@0.3.34-next.3 + - @backstage/plugin-auth-backend@0.15.0-next.3 + - @backstage/plugin-auth-node@0.2.3-next.2 + - @backstage/plugin-azure-devops-backend@0.3.13-next.1 + - @backstage/plugin-graphql-backend@0.1.24-next.1 + - @backstage/plugin-jenkins-backend@0.1.24-next.3 + - @backstage/plugin-permission-backend@0.5.9-next.2 + - @backstage/plugin-permission-common@0.6.3-next.1 + - @backstage/plugin-permission-node@0.6.3-next.2 + - @backstage/plugin-rollbar-backend@0.1.31-next.1 + - @backstage/plugin-techdocs-backend@1.2.0-next.3 + - @backstage/plugin-todo-backend@0.1.31-next.2 + - @backstage/backend-tasks@0.3.3-next.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.2 + - @backstage/plugin-tech-insights-backend@0.5.0-next.3 + - @backstage/plugin-tech-insights-node@0.3.2-next.1 + - @backstage/catalog-model@1.1.0-next.3 + - @backstage/plugin-search-backend-module-elasticsearch@0.2.0-next.2 + - @backstage/plugin-search-backend-node@0.6.3-next.2 + - @backstage/plugin-search-backend@0.5.4-next.2 + - example-app@0.2.73-next.3 + +## 0.2.73-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.7.0-next.2 + - @backstage/plugin-tech-insights-backend@0.5.0-next.2 + - @backstage/plugin-jenkins-backend@0.1.24-next.2 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.2 + - @backstage/plugin-scaffolder-backend@1.4.0-next.2 + - @backstage/plugin-auth-backend@0.15.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-kafka-backend@0.2.27-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + - @backstage/plugin-app-backend@0.3.34-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + - @backstage/plugin-code-coverage-backend@0.1.32-next.2 + - @backstage/plugin-techdocs-backend@1.2.0-next.2 + - @backstage/plugin-badges-backend@0.1.28-next.2 + - @backstage/integration@1.2.2-next.2 + - example-app@0.2.73-next.2 + +## 0.2.73-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.1 + - @backstage/plugin-auth-backend@0.15.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@0.2.0-next.1 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/plugin-techdocs-backend@1.2.0-next.1 + - example-app@0.2.73-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-app-backend@0.3.34-next.1 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-badges-backend@0.1.28-next.1 + - @backstage/plugin-code-coverage-backend@0.1.32-next.1 + - @backstage/plugin-jenkins-backend@0.1.24-next.1 + - @backstage/plugin-kafka-backend@0.2.27-next.1 + - @backstage/plugin-kubernetes-backend@0.7.0-next.1 + - @backstage/plugin-permission-backend@0.5.9-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.1 + - @backstage/plugin-search-backend@0.5.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.1 + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-tech-insights-backend@0.4.2-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.1 + - @backstage/plugin-todo-backend@0.1.31-next.1 + +## 0.2.73-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-tech-insights-backend@0.4.2-next.0 + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + - @backstage/plugin-auth-backend@0.14.2-next.0 + - @backstage/plugin-kubernetes-backend@0.7.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-azure-devops-backend@0.3.13-next.0 + - example-app@0.2.73-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-app-backend@0.3.34-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/plugin-badges-backend@0.1.28-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/plugin-code-coverage-backend@0.1.32-next.0 + - @backstage/plugin-graphql-backend@0.1.24-next.0 + - @backstage/plugin-jenkins-backend@0.1.24-next.0 + - @backstage/plugin-kafka-backend@0.2.27-next.0 + - @backstage/plugin-permission-backend@0.5.9-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + - @backstage/plugin-proxy-backend@0.2.28-next.0 + - @backstage/plugin-rollbar-backend@0.1.31-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.0 + - @backstage/plugin-search-backend@0.5.4-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.6-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.0 + - @backstage/plugin-search-backend-node@0.6.3-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.0 + - @backstage/plugin-tech-insights-node@0.3.2-next.0 + - @backstage/plugin-techdocs-backend@1.1.3-next.0 + - @backstage/plugin-todo-backend@0.1.31-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## 0.2.72 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-tech-insights-backend@0.4.1 + - @backstage/plugin-catalog-backend@1.2.0 + - @backstage/plugin-auth-backend@0.14.1 + - @backstage/plugin-scaffolder-backend@1.3.0 + - @backstage/backend-tasks@0.3.2 + - @backstage/plugin-permission-node@0.6.2 + - @backstage/plugin-kubernetes-backend@0.6.0 + - @backstage/backend-common@0.14.0 + - @backstage/plugin-search-backend@0.5.3 + - @backstage/plugin-auth-node@0.2.2 + - @backstage/integration@1.2.1 + - @backstage/plugin-jenkins-backend@0.1.23 + - @backstage/plugin-search-backend-node@0.6.2 + - @backstage/catalog-client@1.0.3 + - @backstage/plugin-app-backend@0.3.33 + - @backstage/plugin-azure-devops-backend@0.3.12 + - @backstage/plugin-code-coverage-backend@0.1.31 + - @backstage/plugin-graphql-backend@0.1.23 + - @backstage/plugin-permission-backend@0.5.8 + - @backstage/plugin-permission-common@0.6.2 + - @backstage/plugin-rollbar-backend@0.1.30 + - @backstage/plugin-techdocs-backend@1.1.2 + - @backstage/plugin-todo-backend@0.1.30 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.5 + - @backstage/plugin-search-backend-module-pg@0.3.4 + - @backstage/catalog-model@1.0.3 + - @backstage/plugin-tech-insights-node@0.3.1 + - example-app@0.2.72 + - @backstage/plugin-badges-backend@0.1.27 + - @backstage/plugin-kafka-backend@0.2.26 + - @backstage/plugin-proxy-backend@0.2.27 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.17 + +## 0.2.72-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.3.0-next.2 + - @backstage/backend-common@0.14.0-next.2 + - @backstage/plugin-search-backend@0.5.3-next.2 + - @backstage/plugin-auth-backend@0.14.1-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.5-next.2 + - @backstage/integration@1.2.1-next.2 + - @backstage/plugin-techdocs-backend@1.1.2-next.2 + - @backstage/plugin-search-backend-node@0.6.2-next.2 + - example-app@0.2.72-next.2 + - @backstage/backend-tasks@0.3.2-next.2 + - @backstage/plugin-app-backend@0.3.33-next.2 + - @backstage/plugin-auth-node@0.2.2-next.2 + - @backstage/plugin-azure-devops-backend@0.3.12-next.2 + - @backstage/plugin-badges-backend@0.1.27-next.2 + - @backstage/plugin-catalog-backend@1.2.0-next.2 + - @backstage/plugin-code-coverage-backend@0.1.31-next.2 + - @backstage/plugin-graphql-backend@0.1.23-next.2 + - @backstage/plugin-jenkins-backend@0.1.23-next.2 + - @backstage/plugin-kafka-backend@0.2.26-next.2 + - @backstage/plugin-kubernetes-backend@0.6.0-next.2 + - @backstage/plugin-permission-backend@0.5.8-next.2 + - @backstage/plugin-permission-node@0.6.2-next.2 + - @backstage/plugin-proxy-backend@0.2.27-next.1 + - @backstage/plugin-rollbar-backend@0.1.30-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.1-next.1 + - @backstage/plugin-search-backend-module-pg@0.3.4-next.2 + - @backstage/plugin-tech-insights-backend@0.4.1-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.17-next.1 + - @backstage/plugin-tech-insights-node@0.3.1-next.1 + - @backstage/plugin-todo-backend@0.1.30-next.2 + +## 0.2.72-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-tech-insights-backend@0.4.1-next.1 + - @backstage/plugin-auth-backend@0.14.1-next.1 + - @backstage/plugin-jenkins-backend@0.1.23-next.1 + - @backstage/backend-tasks@0.3.2-next.1 + - @backstage/backend-common@0.13.6-next.1 + - @backstage/catalog-client@1.0.3-next.0 + - @backstage/integration@1.2.1-next.1 + - @backstage/plugin-app-backend@0.3.33-next.1 + - @backstage/plugin-auth-node@0.2.2-next.1 + - @backstage/plugin-azure-devops-backend@0.3.12-next.1 + - @backstage/plugin-catalog-backend@1.2.0-next.1 + - @backstage/plugin-code-coverage-backend@0.1.31-next.1 + - @backstage/plugin-graphql-backend@0.1.23-next.1 + - @backstage/plugin-permission-backend@0.5.8-next.1 + - @backstage/plugin-permission-common@0.6.2-next.0 + - @backstage/plugin-permission-node@0.6.2-next.1 + - @backstage/plugin-rollbar-backend@0.1.30-next.1 + - @backstage/plugin-scaffolder-backend@1.3.0-next.1 + - @backstage/plugin-techdocs-backend@1.1.2-next.1 + - @backstage/plugin-todo-backend@0.1.30-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.5-next.1 + - @backstage/plugin-search-backend-node@0.6.2-next.1 + - @backstage/catalog-model@1.0.3-next.0 + - @backstage/plugin-badges-backend@0.1.27-next.1 + - example-app@0.2.72-next.1 + - @backstage/plugin-search-backend@0.5.3-next.1 + - @backstage/plugin-kafka-backend@0.2.26-next.1 + - @backstage/plugin-kubernetes-backend@0.6.0-next.1 + - @backstage/plugin-search-backend-module-pg@0.3.4-next.1 + +## 0.2.72-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.3.2-next.0 + - @backstage/plugin-scaffolder-backend@1.3.0-next.0 + - @backstage/plugin-kubernetes-backend@0.6.0-next.0 + - @backstage/backend-common@0.13.6-next.0 + - @backstage/plugin-auth-backend@0.14.1-next.0 + - @backstage/integration@1.2.1-next.0 + - @backstage/plugin-search-backend-node@0.6.2-next.0 + - @backstage/plugin-catalog-backend@1.2.0-next.0 + - @backstage/plugin-auth-node@0.2.2-next.0 + - @backstage/plugin-techdocs-backend@1.1.2-next.0 + - example-app@0.2.72-next.0 + - @backstage/plugin-app-backend@0.3.33-next.0 + - @backstage/plugin-azure-devops-backend@0.3.12-next.0 + - @backstage/plugin-badges-backend@0.1.27-next.0 + - @backstage/plugin-code-coverage-backend@0.1.31-next.0 + - @backstage/plugin-graphql-backend@0.1.23-next.0 + - @backstage/plugin-jenkins-backend@0.1.23-next.0 + - @backstage/plugin-kafka-backend@0.2.26-next.0 + - @backstage/plugin-permission-backend@0.5.8-next.0 + - @backstage/plugin-permission-node@0.6.2-next.0 + - @backstage/plugin-proxy-backend@0.2.27-next.0 + - @backstage/plugin-rollbar-backend@0.1.30-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.1-next.0 + - @backstage/plugin-search-backend@0.5.3-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.5-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.4-next.0 + - @backstage/plugin-tech-insights-backend@0.4.1-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.17-next.0 + - @backstage/plugin-tech-insights-node@0.3.1-next.0 + - @backstage/plugin-todo-backend@0.1.30-next.0 + +## 0.2.71 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.13.3 + - @backstage/plugin-auth-backend@0.14.0 + - @backstage/plugin-kubernetes-backend@0.5.1 + - @backstage/plugin-catalog-backend@1.1.2 + - @backstage/plugin-tech-insights-backend@0.4.0 + - @backstage/plugin-scaffolder-backend@1.2.0 + - @backstage/backend-tasks@0.3.1 + - @backstage/integration@1.2.0 + - @backstage/plugin-tech-insights-node@0.3.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16 + - @backstage/plugin-rollbar-backend@0.1.29 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.4 + - @backstage/config@1.0.1 + - @backstage/plugin-app-backend@0.3.32 + - @backstage/plugin-techdocs-backend@1.1.1 + - @backstage/plugin-search-backend-node@0.6.1 + - @backstage/plugin-search-backend-module-pg@0.3.3 + - @backstage/plugin-jenkins-backend@0.1.22 + - @backstage/plugin-search-backend@0.5.2 + - @backstage/plugin-auth-node@0.2.1 + - @backstage/plugin-azure-devops-backend@0.3.11 + - example-app@0.2.71 + - @backstage/catalog-client@1.0.2 + - @backstage/catalog-model@1.0.2 + - @backstage/plugin-badges-backend@0.1.26 + - @backstage/plugin-code-coverage-backend@0.1.30 + - @backstage/plugin-graphql-backend@0.1.22 + - @backstage/plugin-kafka-backend@0.2.25 + - @backstage/plugin-permission-backend@0.5.7 + - @backstage/plugin-permission-common@0.6.1 + - @backstage/plugin-permission-node@0.6.1 + - @backstage/plugin-proxy-backend@0.2.26 + - @backstage/plugin-todo-backend@0.1.29 + +## 0.2.71-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.13.3-next.2 + - @backstage/plugin-kubernetes-backend@0.5.1-next.1 + - @backstage/plugin-catalog-backend@1.1.2-next.2 + - @backstage/backend-tasks@0.3.1-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.0-next.1 + - @backstage/plugin-scaffolder-backend@1.2.0-next.1 + - @backstage/config@1.0.1-next.0 + - @backstage/plugin-search-backend-node@0.6.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.3.3-next.1 + - @backstage/plugin-azure-devops-backend@0.3.11-next.1 + - example-app@0.2.71-next.2 + - @backstage/catalog-model@1.0.2-next.0 + - @backstage/integration@1.2.0-next.1 + - @backstage/plugin-app-backend@0.3.32-next.1 + - @backstage/plugin-auth-backend@0.13.1-next.2 + - @backstage/plugin-auth-node@0.2.1-next.1 + - @backstage/plugin-badges-backend@0.1.26-next.1 + - @backstage/plugin-code-coverage-backend@0.1.30-next.1 + - @backstage/plugin-graphql-backend@0.1.22-next.1 + - @backstage/plugin-jenkins-backend@0.1.22-next.1 + - @backstage/plugin-kafka-backend@0.2.25-next.1 + - @backstage/plugin-permission-backend@0.5.7-next.1 + - @backstage/plugin-permission-common@0.6.1-next.0 + - @backstage/plugin-permission-node@0.6.1-next.1 + - @backstage/plugin-proxy-backend@0.2.26-next.1 + - @backstage/plugin-rollbar-backend@0.1.29-next.2 + - @backstage/plugin-search-backend@0.5.2-next.1 + - @backstage/plugin-tech-insights-backend@0.4.0-next.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16-next.2 + - @backstage/plugin-tech-insights-node@0.3.0-next.2 + - @backstage/plugin-techdocs-backend@1.1.1-next.1 + - @backstage/plugin-todo-backend@0.1.29-next.1 + - @backstage/catalog-client@1.0.2-next.0 + +## 0.2.71-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.13.1-next.1 + - @backstage/plugin-tech-insights-backend@0.4.0-next.1 + - @backstage/backend-common@0.13.3-next.1 + - @backstage/plugin-tech-insights-node@0.3.0-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16-next.1 + - @backstage/plugin-catalog-backend@1.1.2-next.1 + - @backstage/plugin-rollbar-backend@0.1.29-next.1 + - example-app@0.2.71-next.1 + +## 0.2.71-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.13.3-next.0 + - @backstage/plugin-scaffolder-backend@1.2.0-next.0 + - @backstage/plugin-kubernetes-backend@0.5.1-next.0 + - @backstage/integration@1.2.0-next.0 + - @backstage/plugin-catalog-backend@1.1.2-next.0 + - @backstage/plugin-app-backend@0.3.32-next.0 + - @backstage/plugin-auth-backend@0.13.1-next.0 + - @backstage/plugin-rollbar-backend@0.1.29-next.0 + - @backstage/plugin-techdocs-backend@1.1.1-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.4-next.0 + - @backstage/plugin-jenkins-backend@0.1.22-next.0 + - @backstage/plugin-search-backend@0.5.2-next.0 + - @backstage/backend-tasks@0.3.1-next.0 + - @backstage/plugin-auth-node@0.2.1-next.0 + - example-app@0.2.71-next.0 + - @backstage/plugin-azure-devops-backend@0.3.11-next.0 + - @backstage/plugin-badges-backend@0.1.26-next.0 + - @backstage/plugin-code-coverage-backend@0.1.30-next.0 + - @backstage/plugin-graphql-backend@0.1.22-next.0 + - @backstage/plugin-kafka-backend@0.2.25-next.0 + - @backstage/plugin-permission-backend@0.5.7-next.0 + - @backstage/plugin-permission-node@0.6.1-next.0 + - @backstage/plugin-proxy-backend@0.2.26-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.7-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.3-next.0 + - @backstage/plugin-search-backend-node@0.6.1-next.0 + - @backstage/plugin-tech-insights-backend@0.3.1-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16-next.0 + - @backstage/plugin-tech-insights-node@0.2.10-next.0 + - @backstage/plugin-todo-backend@0.1.29-next.0 + +## 0.2.70 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.1.0 + - @backstage/plugin-techdocs-backend@1.1.0 + - @backstage/plugin-scaffolder-backend@1.1.0 + - @backstage/integration@1.1.0 + - @backstage/plugin-search-backend@0.5.0 + - @backstage/plugin-auth-backend@0.13.0 + - @backstage/backend-tasks@0.3.0 + - @backstage/plugin-permission-common@0.6.0 + - @backstage/plugin-permission-node@0.6.0 + - @backstage/catalog-model@1.0.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.15 + - @backstage/plugin-kafka-backend@0.2.24 + - @backstage/plugin-auth-node@0.2.0 + - @backstage/plugin-jenkins-backend@0.1.20 + - @backstage/plugin-badges-backend@0.1.25 + - @backstage/plugin-tech-insights-node@0.2.9 + - @backstage/plugin-todo-backend@0.1.28 + - @backstage/backend-common@0.13.2 + - @backstage/plugin-kubernetes-backend@0.5.0 + - @backstage/plugin-search-backend-node@0.6.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.3 + - @backstage/plugin-search-backend-module-pg@0.3.2 + - @backstage/plugin-permission-backend@0.5.6 + - @backstage/plugin-tech-insights-backend@0.3.0 + - @backstage/plugin-azure-devops-backend@0.3.10 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.6 + - example-app@0.2.70 + - @backstage/catalog-client@1.0.1 + - @backstage/plugin-app-backend@0.3.31 + - @backstage/plugin-code-coverage-backend@0.1.29 + - @backstage/plugin-graphql-backend@0.1.21 + - @backstage/plugin-proxy-backend@0.2.25 + - @backstage/plugin-rollbar-backend@0.1.28 + +## 0.2.70-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.13.0-next.2 + - @backstage/plugin-catalog-backend@1.1.0-next.3 + - @backstage/plugin-kafka-backend@0.2.24-next.1 + - @backstage/plugin-search-backend@0.5.0-next.2 + - @backstage/plugin-permission-common@0.6.0-next.1 + - @backstage/plugin-permission-node@0.6.0-next.2 + - @backstage/plugin-jenkins-backend@0.1.20-next.2 + - @backstage/plugin-todo-backend@0.1.28-next.2 + - @backstage/backend-common@0.13.2-next.2 + - @backstage/plugin-kubernetes-backend@0.5.0-next.1 + - @backstage/plugin-search-backend-node@0.6.0-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.6-next.2 + - @backstage/integration@1.1.0-next.2 + - @backstage/plugin-techdocs-backend@1.1.0-next.2 + - example-app@0.2.70-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.3-next.1 + - @backstage/plugin-search-backend-module-pg@0.3.2-next.1 + - @backstage/plugin-app-backend@0.3.31-next.1 + +## 0.2.70-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.1.0-next.1 + - @backstage/plugin-techdocs-backend@1.0.1-next.1 + - @backstage/plugin-scaffolder-backend@1.1.0-next.1 + - @backstage/integration@1.1.0-next.1 + - @backstage/plugin-search-backend@0.5.0-next.1 + - @backstage/backend-tasks@0.3.0-next.1 + - @backstage/plugin-permission-common@0.6.0-next.0 + - @backstage/plugin-permission-node@0.6.0-next.1 + - @backstage/plugin-badges-backend@0.1.25-next.1 + - @backstage/plugin-tech-insights-node@0.2.9-next.1 + - @backstage/plugin-permission-backend@0.5.6-next.1 + - @backstage/backend-common@0.13.2-next.1 + - @backstage/plugin-auth-backend@0.13.0-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.15-next.1 + - @backstage/plugin-tech-insights-backend@0.3.0-next.1 + - @backstage/plugin-jenkins-backend@0.1.20-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.6-next.1 + - @backstage/plugin-code-coverage-backend@0.1.29-next.1 + - @backstage/plugin-todo-backend@0.1.28-next.1 + - example-app@0.2.70-next.1 + +## 0.2.70-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.0.1-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.15-next.0 + - @backstage/plugin-search-backend@0.5.0-next.0 + - @backstage/plugin-auth-node@0.2.0-next.0 + - @backstage/plugin-auth-backend@0.13.0-next.0 + - @backstage/plugin-catalog-backend@1.0.1-next.0 + - @backstage/plugin-search-backend-node@0.5.3-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.3-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.2-next.0 + - @backstage/backend-common@0.13.2-next.0 + - @backstage/integration@1.0.1-next.0 + - @backstage/plugin-tech-insights-backend@0.2.11-next.0 + - @backstage/plugin-techdocs-backend@1.0.1-next.0 + - @backstage/plugin-jenkins-backend@0.1.20-next.0 + - example-app@0.2.70-next.0 + - @backstage/catalog-client@1.0.1-next.0 + - @backstage/plugin-badges-backend@0.1.25-next.0 + - @backstage/plugin-code-coverage-backend@0.1.29-next.0 + - @backstage/plugin-kafka-backend@0.2.24-next.0 + - @backstage/plugin-kubernetes-backend@0.4.14-next.0 + - @backstage/plugin-scaffolder-backend@1.0.1-next.0 + - @backstage/plugin-todo-backend@0.1.28-next.0 + - @backstage/plugin-app-backend@0.3.31-next.0 + - @backstage/plugin-permission-backend@0.5.6-next.0 + - @backstage/plugin-permission-node@0.5.6-next.0 + - @backstage/backend-tasks@0.2.2-next.0 + - @backstage/plugin-azure-devops-backend@0.3.10-next.0 + - @backstage/plugin-graphql-backend@0.1.21-next.0 + - @backstage/plugin-proxy-backend@0.2.25-next.0 + - @backstage/plugin-rollbar-backend@0.1.28-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.6-next.0 + - @backstage/plugin-tech-insights-node@0.2.9-next.0 + +## 0.2.69 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app-backend@0.3.30 + - @backstage/plugin-azure-devops-backend@0.3.9 + - @backstage/plugin-badges-backend@0.1.24 + - @backstage/plugin-catalog-backend@1.0.0 + - @backstage/plugin-jenkins-backend@0.1.19 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.5 + - @backstage/plugin-tech-insights-backend@0.2.10 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.14 + - @backstage/plugin-todo-backend@0.1.27 + - @backstage/plugin-kubernetes-backend@0.4.13 + - @backstage/plugin-scaffolder-backend@1.0.0 + - @backstage/backend-common@0.13.1 + - @backstage/backend-tasks@0.2.1 + - @backstage/plugin-auth-backend@0.12.2 + - @backstage/plugin-code-coverage-backend@0.1.28 + - @backstage/catalog-model@1.0.0 + - @backstage/integration@1.0.0 + - @backstage/catalog-client@1.0.0 + - @backstage/config@1.0.0 + - @backstage/plugin-techdocs-backend@1.0.0 + - @backstage/plugin-permission-common@0.5.3 + - @backstage/plugin-search-backend-node@0.5.2 + - example-app@0.2.69 + - @backstage/plugin-auth-node@0.1.6 + - @backstage/plugin-graphql-backend@0.1.20 + - @backstage/plugin-kafka-backend@0.2.23 + - @backstage/plugin-permission-backend@0.5.5 + - @backstage/plugin-permission-node@0.5.5 + - @backstage/plugin-proxy-backend@0.2.24 + - @backstage/plugin-rollbar-backend@0.1.27 + - @backstage/plugin-search-backend@0.4.8 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.2 + - @backstage/plugin-tech-insights-node@0.2.8 + +## 0.2.68 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.13.0 + - @backstage/backend-tasks@0.2.0 + - @backstage/plugin-app-backend@0.3.29 + - @backstage/plugin-auth-backend@0.12.1 + - @backstage/plugin-catalog-backend@0.24.0 + - @backstage/plugin-scaffolder-backend@0.18.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.4 + - @backstage/plugin-kubernetes-backend@0.4.12 + - @backstage/plugin-rollbar-backend@0.1.26 + - @backstage/plugin-techdocs-backend@0.14.2 + - @backstage/catalog-model@0.13.0 + - @backstage/plugin-badges-backend@0.1.23 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.1 + - @backstage/plugin-search-backend-module-pg@0.3.1 + - @backstage/plugin-search-backend-node@0.5.1 + - @backstage/plugin-search-backend@0.4.7 + - @backstage/catalog-client@0.9.0 + - example-app@0.2.68 + - @backstage/plugin-auth-node@0.1.5 + - @backstage/plugin-azure-devops-backend@0.3.8 + - @backstage/plugin-code-coverage-backend@0.1.27 + - @backstage/plugin-graphql-backend@0.1.19 + - @backstage/plugin-jenkins-backend@0.1.18 + - @backstage/plugin-kafka-backend@0.2.22 + - @backstage/plugin-permission-backend@0.5.4 + - @backstage/plugin-permission-node@0.5.4 + - @backstage/plugin-proxy-backend@0.2.23 + - @backstage/plugin-tech-insights-backend@0.2.9 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.13 + - @backstage/plugin-tech-insights-node@0.2.7 + - @backstage/plugin-todo-backend@0.1.26 + +## 0.2.68-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.13.0-next.0 + - @backstage/backend-tasks@0.2.0-next.0 + - @backstage/plugin-app-backend@0.3.29-next.0 + - @backstage/plugin-auth-backend@0.12.1-next.0 + - @backstage/plugin-catalog-backend@0.24.0-next.0 + - @backstage/plugin-scaffolder-backend@0.18.0-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.4-next.0 + - @backstage/plugin-kubernetes-backend@0.4.12-next.0 + - @backstage/plugin-rollbar-backend@0.1.26-next.0 + - @backstage/plugin-techdocs-backend@0.14.2-next.0 + - @backstage/catalog-model@0.13.0-next.0 + - @backstage/plugin-badges-backend@0.1.23-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.1-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.1-next.0 + - @backstage/plugin-search-backend-node@0.5.1-next.0 + - @backstage/plugin-search-backend@0.4.7-next.0 + - @backstage/catalog-client@0.9.0-next.0 + - @backstage/plugin-auth-node@0.1.5-next.0 + - @backstage/plugin-azure-devops-backend@0.3.8-next.0 + - @backstage/plugin-code-coverage-backend@0.1.27-next.0 + - @backstage/plugin-graphql-backend@0.1.19-next.0 + - @backstage/plugin-jenkins-backend@0.1.18-next.0 + - @backstage/plugin-kafka-backend@0.2.22-next.0 + - @backstage/plugin-permission-backend@0.5.4-next.0 + - @backstage/plugin-permission-node@0.5.4-next.0 + - @backstage/plugin-proxy-backend@0.2.23-next.0 + - @backstage/plugin-tech-insights-backend@0.2.9-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.13-next.0 + - @backstage/plugin-tech-insights-node@0.2.7-next.0 + - @backstage/plugin-todo-backend@0.1.26-next.0 + - example-app@0.2.68-next.0 + +## 0.2.67 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@0.12.0 + - @backstage/catalog-client@0.8.0 + - @backstage/plugin-catalog-backend@0.23.0 + - @backstage/backend-common@0.12.0 + - @backstage/plugin-scaffolder-backend@0.17.3 + - @backstage/plugin-techdocs-backend@0.14.1 + - @backstage/plugin-auth-backend@0.12.0 + - @backstage/plugin-badges-backend@0.1.22 + - @backstage/plugin-code-coverage-backend@0.1.26 + - @backstage/plugin-jenkins-backend@0.1.17 + - @backstage/plugin-todo-backend@0.1.25 + - @backstage/integration@0.8.0 + - @backstage/plugin-permission-common@0.5.2 + - @backstage/plugin-permission-node@0.5.3 + - @backstage/plugin-search-backend-node@0.5.0 + - @backstage/plugin-search-backend-module-pg@0.3.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.0 + - @backstage/plugin-tech-insights-backend@0.2.8 + - example-app@0.2.67 + - @backstage/plugin-auth-node@0.1.4 + - @backstage/plugin-kafka-backend@0.2.21 + - @backstage/plugin-kubernetes-backend@0.4.11 + - @backstage/backend-tasks@0.1.10 + - @backstage/plugin-app-backend@0.3.28 + - @backstage/plugin-azure-devops-backend@0.3.7 + - @backstage/plugin-graphql-backend@0.1.18 + - @backstage/plugin-permission-backend@0.5.3 + - @backstage/plugin-proxy-backend@0.2.22 + - @backstage/plugin-rollbar-backend@0.1.25 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.3 + - @backstage/plugin-search-backend@0.4.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.12 + - @backstage/plugin-tech-insights-node@0.2.6 + +## 0.2.66 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.11.0 + - @backstage/plugin-catalog-backend@0.22.0 + - @backstage/plugin-scaffolder-backend@0.17.0 + - @backstage/plugin-graphql-backend@0.1.17 + - @backstage/plugin-auth-backend@0.11.0 + - @backstage/plugin-kubernetes-backend@0.4.10 + - @backstage/plugin-code-coverage-backend@0.1.25 + - @backstage/plugin-jenkins-backend@0.1.16 + - @backstage/plugin-tech-insights-backend@0.2.7 + - @backstage/plugin-todo-backend@0.1.24 + - @backstage/catalog-model@0.11.0 + - @backstage/catalog-client@0.7.2 + - @backstage/plugin-badges-backend@0.1.21 + - @backstage/backend-tasks@0.1.9 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.2 + - @backstage/plugin-techdocs-backend@0.14.0 + - @backstage/plugin-permission-node@0.5.2 + - @backstage/integration@0.7.5 + - example-app@0.2.66 + - @backstage/plugin-app-backend@0.3.27 + - @backstage/plugin-auth-node@0.1.3 + - @backstage/plugin-azure-devops-backend@0.3.6 + - @backstage/plugin-kafka-backend@0.2.20 + - @backstage/plugin-permission-backend@0.5.2 + - @backstage/plugin-proxy-backend@0.2.21 + - @backstage/plugin-rollbar-backend@0.1.24 + - @backstage/plugin-search-backend@0.4.5 + - @backstage/plugin-search-backend-module-pg@0.2.9 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.11 + - @backstage/plugin-tech-insights-node@0.2.5 + +## 0.2.66 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.10.9 + - @backstage/backend-tasks@0.1.8 + - @backstage/catalog-client@0.7.1 + - @backstage/catalog-model@0.10.1 + - @backstage/config@0.1.15 + - @backstage/integration@0.7.4 + - @backstage/plugin-app-backend@0.3.26 + - @backstage/plugin-auth-backend@0.10.2 + - @backstage/plugin-auth-node@0.1.2 + - @backstage/plugin-azure-devops-backend@0.3.5 + - @backstage/plugin-badges-backend@0.1.20 + - @backstage/plugin-catalog-backend@0.21.5 + - @backstage/plugin-code-coverage-backend@0.1.24 + - @backstage/plugin-graphql-backend@0.1.16 + - @backstage/plugin-jenkins-backend@0.1.15 + - @backstage/plugin-kafka-backend@0.2.19 + - @backstage/plugin-kubernetes-backend@0.4.9 + - @backstage/plugin-permission-backend@0.5.1 + - @backstage/plugin-permission-common@0.5.1 + - @backstage/plugin-permission-node@0.5.1 + - @backstage/plugin-proxy-backend@0.2.20 + - @backstage/plugin-rollbar-backend@0.1.23 + - @backstage/plugin-scaffolder-backend@0.16.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.1 + - @backstage/plugin-search-backend@0.4.4 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.10 + - @backstage/plugin-search-backend-module-pg@0.2.8 + - @backstage/plugin-search-backend-node@0.4.7 + - @backstage/plugin-tech-insights-backend@0.2.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.10 + - @backstage/plugin-tech-insights-node@0.2.4 + - @backstage/plugin-techdocs-backend@0.13.5 + - @backstage/plugin-todo-backend@0.1.23 + +## 0.2.65 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@0.13.4 + - @backstage/plugin-catalog-backend@0.21.4 + - @backstage/backend-common@0.10.8 + - @backstage/catalog-client@0.7.0 + - @backstage/integration@0.7.3 + - @backstage/plugin-auth-backend@0.10.1 + - @backstage/plugin-auth-node@0.1.1 + - @backstage/plugin-permission-backend@0.5.0 + - @backstage/plugin-permission-common@0.5.0 + - @backstage/plugin-rollbar-backend@0.1.22 + - @backstage/plugin-scaffolder-backend@0.16.0 + - @backstage/backend-tasks@0.1.7 + - @backstage/catalog-model@0.10.0 + - @backstage/config@0.1.14 + - @backstage/plugin-app-backend@0.3.25 + - @backstage/plugin-azure-devops-backend@0.3.4 + - @backstage/plugin-badges-backend@0.1.19 + - @backstage/plugin-code-coverage-backend@0.1.23 + - @backstage/plugin-graphql-backend@0.1.15 + - @backstage/plugin-jenkins-backend@0.1.14 + - @backstage/plugin-kafka-backend@0.2.18 + - @backstage/plugin-kubernetes-backend@0.4.8 + - @backstage/plugin-permission-node@0.5.0 + - @backstage/plugin-proxy-backend@0.2.19 + - @backstage/plugin-scaffolder-backend-module-rails@0.3.0 + - @backstage/plugin-search-backend@0.4.3 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.9 + - @backstage/plugin-search-backend-module-pg@0.2.7 + - @backstage/plugin-search-backend-node@0.4.6 + - @backstage/plugin-tech-insights-backend@0.2.5 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.9 + - @backstage/plugin-tech-insights-node@0.2.3 + - @backstage/plugin-todo-backend@0.1.22 + - example-app@0.2.65 + +## 0.2.64 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@0.6.0 + - @backstage/plugin-auth-backend@0.10.0 + - @backstage/backend-common@0.10.7 + - @backstage/backend-tasks@0.1.6 + - @backstage/plugin-app-backend@0.3.24 + - @backstage/plugin-catalog-backend@0.21.3 + - @backstage/plugin-code-coverage-backend@0.1.22 + - @backstage/plugin-scaffolder-backend@0.15.24 + - @backstage/plugin-search-backend-module-pg@0.2.6 + - @backstage/plugin-tech-insights-backend@0.2.4 + - @backstage/plugin-techdocs-backend@0.13.3 + - @backstage/plugin-auth-node@0.1.0 + - @backstage/plugin-permission-backend@0.4.3 + - @backstage/plugin-search-backend@0.4.2 + - @backstage/plugin-badges-backend@0.1.18 + - @backstage/plugin-jenkins-backend@0.1.13 + - @backstage/plugin-todo-backend@0.1.21 + - @backstage/plugin-permission-node@0.4.3 + - example-app@0.2.64 + - @backstage/plugin-azure-devops-backend@0.3.3 + - @backstage/plugin-graphql-backend@0.1.14 + - @backstage/plugin-kafka-backend@0.2.17 + - @backstage/plugin-kubernetes-backend@0.4.7 + - @backstage/plugin-proxy-backend@0.2.18 + - @backstage/plugin-rollbar-backend@0.1.21 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.8 + - @backstage/plugin-tech-insights-node@0.2.2 + +## 0.2.64-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.10.0-next.0 + - @backstage/backend-common@0.10.7-next.0 + - @backstage/backend-tasks@0.1.6-next.0 + - @backstage/plugin-app-backend@0.3.24-next.0 + - @backstage/plugin-catalog-backend@0.21.3-next.0 + - @backstage/plugin-code-coverage-backend@0.1.22-next.0 + - @backstage/plugin-scaffolder-backend@0.15.24-next.0 + - @backstage/plugin-search-backend-module-pg@0.2.6-next.0 + - @backstage/plugin-tech-insights-backend@0.2.4-next.0 + - @backstage/plugin-techdocs-backend@0.13.3-next.0 + - example-app@0.2.64-next.0 + - @backstage/plugin-azure-devops-backend@0.3.3-next.0 + - @backstage/plugin-badges-backend@0.1.18-next.0 + - @backstage/plugin-graphql-backend@0.1.14-next.0 + - @backstage/plugin-jenkins-backend@0.1.13-next.0 + - @backstage/plugin-kafka-backend@0.2.17-next.0 + - @backstage/plugin-kubernetes-backend@0.4.7-next.0 + - @backstage/plugin-permission-backend@0.4.3-next.0 + - @backstage/plugin-permission-node@0.4.3-next.0 + - @backstage/plugin-proxy-backend@0.2.18-next.0 + - @backstage/plugin-rollbar-backend@0.1.21-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.6-next.0 + - @backstage/plugin-search-backend@0.4.2-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.8-next.0 + - @backstage/plugin-tech-insights-node@0.2.2-next.0 + - @backstage/plugin-todo-backend@0.1.21-next.0 + +## 0.2.63 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.9.0 + - @backstage/plugin-rollbar-backend@0.1.20 + - @backstage/plugin-catalog-backend@0.21.2 + - @backstage/plugin-scaffolder-backend@0.15.23 + - @backstage/plugin-proxy-backend@0.2.17 + - @backstage/backend-common@0.10.6 + - example-app@0.2.63 + - @backstage/backend-tasks@0.1.5 + - @backstage/plugin-app-backend@0.3.23 + - @backstage/plugin-azure-devops-backend@0.3.2 + - @backstage/plugin-badges-backend@0.1.17 + - @backstage/plugin-code-coverage-backend@0.1.21 + - @backstage/plugin-graphql-backend@0.1.13 + - @backstage/plugin-jenkins-backend@0.1.12 + - @backstage/plugin-kafka-backend@0.2.16 + - @backstage/plugin-kubernetes-backend@0.4.6 + - @backstage/plugin-permission-backend@0.4.2 + - @backstage/plugin-permission-node@0.4.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.5 + - @backstage/plugin-search-backend@0.4.1 + - @backstage/plugin-search-backend-module-pg@0.2.5 + - @backstage/plugin-tech-insights-backend@0.2.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.7 + - @backstage/plugin-tech-insights-node@0.2.1 + - @backstage/plugin-techdocs-backend@0.13.2 + - @backstage/plugin-todo-backend@0.1.20 + +## 0.2.63-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.9.0-next.1 + - @backstage/backend-common@0.10.6-next.0 + - example-app@0.2.63-next.1 + - @backstage/plugin-catalog-backend@0.21.2-next.1 + - @backstage/plugin-techdocs-backend@0.13.2-next.0 + - @backstage/backend-tasks@0.1.5-next.0 + - @backstage/plugin-app-backend@0.3.23-next.0 + - @backstage/plugin-azure-devops-backend@0.3.2-next.0 + - @backstage/plugin-badges-backend@0.1.17-next.0 + - @backstage/plugin-code-coverage-backend@0.1.21-next.0 + - @backstage/plugin-graphql-backend@0.1.13-next.0 + - @backstage/plugin-jenkins-backend@0.1.12-next.0 + - @backstage/plugin-kafka-backend@0.2.16-next.0 + - @backstage/plugin-kubernetes-backend@0.4.6-next.0 + - @backstage/plugin-permission-backend@0.4.2-next.1 + - @backstage/plugin-permission-node@0.4.2-next.1 + - @backstage/plugin-proxy-backend@0.2.17-next.1 + - @backstage/plugin-rollbar-backend@0.1.20-next.1 + - @backstage/plugin-scaffolder-backend@0.15.23-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.5-next.1 + - @backstage/plugin-search-backend@0.4.1-next.1 + - @backstage/plugin-search-backend-module-pg@0.2.5-next.0 + - @backstage/plugin-tech-insights-backend@0.2.3-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.7-next.0 + - @backstage/plugin-tech-insights-node@0.2.1-next.0 + - @backstage/plugin-todo-backend@0.1.20-next.0 + +## 0.2.63-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.9.0-next.0 + - @backstage/plugin-rollbar-backend@0.1.20-next.0 + - @backstage/plugin-catalog-backend@0.21.2-next.0 + - @backstage/plugin-scaffolder-backend@0.15.23-next.0 + - @backstage/plugin-proxy-backend@0.2.17-next.0 + - @backstage/plugin-permission-backend@0.4.2-next.0 + - @backstage/plugin-permission-node@0.4.2-next.0 + - @backstage/plugin-search-backend@0.4.1-next.0 + - example-app@0.2.63-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.5-next.0 + +## 0.2.62 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@0.4.5 + - @backstage/plugin-catalog-backend@0.21.1 + - @backstage/plugin-scaffolder-backend@0.15.22 + - @backstage/plugin-kubernetes-backend@0.4.5 + - @backstage/plugin-auth-backend@0.8.0 + - @backstage/plugin-search-backend@0.4.0 + - @backstage/plugin-tech-insights-backend@0.2.2 + - @backstage/plugin-techdocs-backend@0.13.1 + - @backstage/backend-common@0.10.5 + - example-app@0.2.62 + - @backstage/plugin-permission-backend@0.4.1 + - @backstage/plugin-permission-node@0.4.1 + +## 0.2.61 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.7.0 + - @backstage/plugin-permission-backend@0.4.0 + - @backstage/plugin-catalog-backend@0.21.0 + - @backstage/plugin-kubernetes-backend@0.4.4 + - @backstage/integration@0.7.2 + - @backstage/plugin-permission-common@0.4.0 + - @backstage/plugin-search-backend@0.3.1 + - @backstage/plugin-techdocs-backend@0.13.0 + - @backstage/backend-common@0.10.4 + - @backstage/config@0.1.13 + - @backstage/plugin-app-backend@0.3.22 + - @backstage/plugin-permission-node@0.4.0 + - @backstage/plugin-scaffolder-backend@0.15.21 + - @backstage/plugin-tech-insights-backend@0.2.0 + - @backstage/plugin-tech-insights-node@0.2.0 + - @backstage/catalog-model@0.9.10 + - example-app@0.2.61 + - @backstage/backend-tasks@0.1.4 + - @backstage/catalog-client@0.5.5 + - @backstage/plugin-azure-devops-backend@0.3.1 + - @backstage/plugin-badges-backend@0.1.16 + - @backstage/plugin-code-coverage-backend@0.1.20 + - @backstage/plugin-graphql-backend@0.1.12 + - @backstage/plugin-jenkins-backend@0.1.11 + - @backstage/plugin-kafka-backend@0.2.15 + - @backstage/plugin-proxy-backend@0.2.16 + - @backstage/plugin-rollbar-backend@0.1.19 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.4 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.8 + - @backstage/plugin-search-backend-module-pg@0.2.4 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.6 + - @backstage/plugin-todo-backend@0.1.19 + +## 0.2.61-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.7.0-next.0 + - @backstage/plugin-permission-backend@0.4.0-next.0 + - @backstage/plugin-catalog-backend@0.21.0-next.0 + - @backstage/plugin-permission-common@0.4.0-next.0 + - @backstage/backend-common@0.10.4-next.0 + - @backstage/config@0.1.13-next.0 + - @backstage/plugin-app-backend@0.3.22-next.0 + - @backstage/plugin-permission-node@0.4.0-next.0 + - @backstage/plugin-tech-insights-backend@0.2.0-next.0 + - @backstage/plugin-tech-insights-node@0.2.0-next.0 + - @backstage/catalog-model@0.9.10-next.0 + - example-app@0.2.61-next.0 + - @backstage/plugin-scaffolder-backend@0.15.21-next.0 + - @backstage/backend-tasks@0.1.4-next.0 + - @backstage/catalog-client@0.5.5-next.0 + - @backstage/integration@0.7.2-next.0 + - @backstage/plugin-azure-devops-backend@0.3.1-next.0 + - @backstage/plugin-badges-backend@0.1.16-next.0 + - @backstage/plugin-code-coverage-backend@0.1.20-next.0 + - @backstage/plugin-graphql-backend@0.1.12-next.0 + - @backstage/plugin-jenkins-backend@0.1.11-next.0 + - @backstage/plugin-kafka-backend@0.2.15-next.0 + - @backstage/plugin-kubernetes-backend@0.4.4-next.0 + - @backstage/plugin-proxy-backend@0.2.16-next.0 + - @backstage/plugin-rollbar-backend@0.1.19-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.4-next.0 + - @backstage/plugin-search-backend@0.3.1-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.8-next.0 + - @backstage/plugin-search-backend-module-pg@0.2.4-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.6-next.0 + - @backstage/plugin-techdocs-backend@0.12.4-next.0 + - @backstage/plugin-todo-backend@0.1.19-next.0 + +## 0.2.60 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/plugin-scaffolder-backend@0.15.20 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-todo-backend@0.1.18 + - @backstage/plugin-catalog-backend@0.20.0 + - @backstage/plugin-tech-insights-backend@0.1.5 + - @backstage/plugin-permission-node@0.3.0 + - @backstage/plugin-auth-backend@0.6.2 + - @backstage/plugin-code-coverage-backend@0.1.19 + - @backstage/plugin-search-backend-node@0.4.4 + - @backstage/plugin-techdocs-backend@0.12.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.5 + - @backstage/plugin-permission-backend@0.3.0 + - @backstage/plugin-graphql-backend@0.1.11 + - @backstage/plugin-kubernetes-backend@0.4.3 + - example-app@0.2.60 + - @backstage/backend-tasks@0.1.3 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/plugin-badges-backend@0.1.15 + - @backstage/plugin-kafka-backend@0.2.14 + - @backstage/plugin-permission-common@0.3.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.3 + +## 0.2.59 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-rollbar-backend@0.1.18 + - @backstage/plugin-auth-backend@0.6.0 + - @backstage/backend-common@0.10.1 + - @backstage/plugin-app-backend@0.3.21 + - @backstage/plugin-catalog-backend@0.19.4 + - @backstage/plugin-scaffolder-backend@0.15.19 + - @backstage/integration@0.7.0 + - @backstage/plugin-techdocs-backend@0.12.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.4 + - @backstage/plugin-permission-backend@0.2.3 + - @backstage/plugin-permission-node@0.2.3 + - @backstage/plugin-code-coverage-backend@0.1.18 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.2 + - @backstage/plugin-todo-backend@0.1.17 + +## 0.2.58 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.10.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.1 + - @backstage/catalog-client@0.5.3 + - @backstage/plugin-rollbar-backend@0.1.17 + - @backstage/plugin-auth-backend@0.5.2 + - @backstage/plugin-permission-common@0.3.0 + - @backstage/plugin-search-backend@0.3.0 + - @backstage/plugin-techdocs-backend@0.12.1 + - @backstage/plugin-jenkins-backend@0.1.10 + - @backstage/plugin-permission-node@0.2.2 + - example-app@0.2.58 + - @backstage/plugin-app-backend@0.3.20 + - @backstage/plugin-azure-devops-backend@0.2.6 + - @backstage/plugin-badges-backend@0.1.14 + - @backstage/plugin-catalog-backend@0.19.3 + - @backstage/plugin-code-coverage-backend@0.1.17 + - @backstage/plugin-graphql-backend@0.1.10 + - @backstage/plugin-kafka-backend@0.2.13 + - @backstage/plugin-kubernetes-backend@0.4.1 + - @backstage/plugin-permission-backend@0.2.2 + - @backstage/plugin-proxy-backend@0.2.15 + - @backstage/plugin-scaffolder-backend@0.15.18 + - @backstage/plugin-search-backend-module-pg@0.2.3 + - @backstage/plugin-tech-insights-backend@0.1.4 + - @backstage/plugin-tech-insights-node@0.1.2 + - @backstage/plugin-todo-backend@0.1.16 + +## 0.2.57 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@0.0.7 + - @backstage/plugin-catalog-backend@0.19.2 + - @backstage/plugin-scaffolder-backend@0.15.17 + - @backstage/backend-common@0.9.14 + - @backstage/plugin-azure-devops-backend@0.2.5 + - @backstage/plugin-auth-backend@0.5.1 + - @backstage/catalog-model@0.9.8 + - example-app@0.2.57 + +## 0.2.56 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.5.0 + - @backstage/plugin-scaffolder-backend@0.15.16 + - @backstage/plugin-kubernetes-backend@0.4.0 + - @backstage/backend-common@0.9.13 + - @backstage/plugin-catalog-backend@0.19.1 + - @backstage/plugin-search-backend@0.2.8 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.6 + - @backstage/plugin-search-backend-module-pg@0.2.2 + - @backstage/plugin-techdocs-backend@0.12.0 + - @backstage/plugin-todo-backend@0.1.15 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.0 + - @backstage/plugin-azure-devops-backend@0.2.4 + - example-app@0.2.56 + +## 0.2.55 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@0.6.10 + - @backstage/plugin-scaffolder-backend@0.15.15 + - @backstage/plugin-auth-backend@0.4.10 + - @backstage/plugin-kubernetes-backend@0.3.20 + - @backstage/plugin-badges-backend@0.1.13 + - @backstage/plugin-catalog-backend@0.19.0 + - @backstage/plugin-code-coverage-backend@0.1.16 + - @backstage/plugin-jenkins-backend@0.1.9 + - @backstage/plugin-tech-insights-backend@0.1.3 + - @backstage/plugin-techdocs-backend@0.11.0 + - @backstage/plugin-todo-backend@0.1.14 + - @backstage/backend-common@0.9.12 + - @backstage/plugin-azure-devops-backend@0.2.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.2 + - @backstage/plugin-tech-insights-node@0.1.1 + - example-app@0.2.55 + +## 0.2.54 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.3.19 + - @backstage/plugin-tech-insights-backend@0.1.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.1 + - @backstage/plugin-auth-backend@0.4.9 + - @backstage/plugin-scaffolder-backend@0.15.14 + - @backstage/plugin-catalog-backend@0.18.0 + - @backstage/plugin-kafka-backend@0.2.12 + - @backstage/backend-common@0.9.11 + - @backstage/plugin-azure-devops-backend@0.2.2 + - @backstage/plugin-badges-backend@0.1.12 + - @backstage/plugin-code-coverage-backend@0.1.15 + - @backstage/plugin-jenkins-backend@0.1.8 + - @backstage/plugin-proxy-backend@0.2.14 + - @backstage/plugin-rollbar-backend@0.1.16 + - @backstage/plugin-search-backend@0.2.7 + - @backstage/plugin-techdocs-backend@0.10.9 + +## 0.2.52 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.9.9 + - @backstage/plugin-jenkins-backend@0.1.7 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.5 + - @backstage/plugin-scaffolder-backend@0.15.12 + - @backstage/plugin-azure-devops-backend@0.2.0 + - @backstage/catalog-client@0.5.1 + - @backstage/plugin-auth-backend@0.4.7 + - @backstage/plugin-catalog-backend@0.17.3 + - @backstage/plugin-scaffolder-backend-module-rails@0.1.7 + +## 0.2.50 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.4.4 + - @backstage/integration@0.6.8 + - @backstage/plugin-scaffolder-backend@0.15.8 + - @backstage/plugin-catalog-backend@0.17.0 + - @backstage/plugin-azure-devops-backend@0.1.2 + - @backstage/plugin-code-coverage-backend@0.1.13 + - @backstage/plugin-kubernetes-backend@0.3.17 + - example-app@0.2.50 + +## 0.2.49 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@0.16.0 + - @backstage/catalog-model@0.9.4 + - @backstage/plugin-proxy-backend@0.2.13 + - @backstage/plugin-auth-backend@0.4.3 + - @backstage/backend-common@0.9.6 + - @backstage/catalog-client@0.5.0 + - @backstage/integration@0.6.7 + - @backstage/plugin-scaffolder-backend@0.15.7 + - example-app@0.2.49 + - @backstage/plugin-badges-backend@0.1.11 + - @backstage/plugin-code-coverage-backend@0.1.12 + - @backstage/plugin-jenkins-backend@0.1.6 + - @backstage/plugin-techdocs-backend@0.10.4 + - @backstage/plugin-todo-backend@0.1.13 + +## 0.2.48 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.9.5 + - @backstage/plugin-catalog-backend@0.15.0 + - @backstage/plugin-azure-devops-backend@0.1.1 + - @backstage/integration@0.6.6 + - @backstage/plugin-auth-backend@0.4.2 + - example-app@0.2.48 + +## 0.2.47 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@0.14.0 + - @backstage/integration@0.6.5 + - @backstage/catalog-client@0.4.0 + - @backstage/catalog-model@0.9.3 + - @backstage/backend-common@0.9.4 + - @backstage/config@0.1.10 + - @backstage/plugin-kafka-backend@0.2.10 + - @backstage/plugin-kubernetes-backend@0.3.16 + - @backstage/plugin-rollbar-backend@0.1.15 + - @backstage/plugin-search-backend-module-pg@0.2.1 + - example-app@0.2.47 + - @backstage/plugin-auth-backend@0.4.1 + - @backstage/plugin-badges-backend@0.1.10 + - @backstage/plugin-code-coverage-backend@0.1.11 + - @backstage/plugin-jenkins-backend@0.1.5 + - @backstage/plugin-scaffolder-backend@0.15.6 + - @backstage/plugin-techdocs-backend@0.10.3 + - @backstage/plugin-todo-backend@0.1.12 + +## 0.2.46 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.4.0 + - @backstage/plugin-scaffolder-backend@0.15.5 + - @backstage/backend-common@0.9.3 + - @backstage/plugin-catalog-backend@0.13.8 + - @backstage/plugin-techdocs-backend@0.10.2 + - @backstage/integration@0.6.4 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.4 + - example-app@0.2.46 + +## 0.2.44 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@0.13.6 + - @backstage/plugin-scaffolder-backend@0.15.3 + - @backstage/plugin-techdocs-backend@0.10.1 + - @backstage/plugin-auth-backend@0.3.24 + - @backstage/integration@0.6.3 + - @backstage/plugin-search-backend@0.2.6 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.3 + - @backstage/plugin-search-backend-module-pg@0.2.0 + - @backstage/plugin-search-backend-node@0.4.2 + - @backstage/catalog-model@0.9.1 + - @backstage/backend-common@0.9.1 + - example-app@0.2.44 + +## 0.2.43 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.9.0 + - @backstage/plugin-catalog-backend@0.13.5 + - @backstage/plugin-search-backend-module-pg@0.1.3 + - @backstage/plugin-auth-backend@0.3.23 + - @backstage/plugin-scaffolder-backend@0.15.2 + - @backstage/integration@0.6.2 + - @backstage/config@0.1.8 + - @backstage/plugin-kubernetes-backend@0.3.15 + - @backstage/plugin-techdocs-backend@0.10.0 + - @backstage/plugin-jenkins-backend@0.1.4 + - @backstage/plugin-app-backend@0.3.16 + - @backstage/plugin-badges-backend@0.1.9 + - @backstage/plugin-code-coverage-backend@0.1.10 + - @backstage/plugin-graphql-backend@0.1.9 + - @backstage/plugin-kafka-backend@0.2.9 + - @backstage/plugin-proxy-backend@0.2.12 + - @backstage/plugin-rollbar-backend@0.1.14 + - @backstage/plugin-scaffolder-backend-module-rails@0.1.5 + - @backstage/plugin-search-backend@0.2.5 + - @backstage/plugin-todo-backend@0.1.11 + - example-app@0.2.43 + +## 0.2.41 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.3.20 + - @backstage/integration@0.6.0 + - @backstage/plugin-scaffolder-backend@0.15.0 + - @backstage/backend-common@0.8.9 + - @backstage/plugin-kubernetes-backend@0.3.14 + - @backstage/plugin-search-backend-module-elasticsearch@0.0.2 + - @backstage/plugin-search-backend-module-pg@0.1.1 + - @backstage/plugin-catalog-backend@0.13.2 + - @backstage/plugin-code-coverage-backend@0.1.9 + - @backstage/plugin-scaffolder-backend-module-rails@0.1.4 + - @backstage/plugin-techdocs-backend@0.9.2 + - @backstage/plugin-todo-backend@0.1.9 + - example-app@0.2.41 + +## 0.2.38 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.3.11 + - @backstage/catalog-client@0.3.17 + - @backstage/plugin-auth-backend@0.3.18 + - @backstage/plugin-jenkins-backend@0.1.2 + - @backstage/backend-common@0.8.7 + - @backstage/plugin-techdocs-backend@0.9.0 + - @backstage/plugin-scaffolder-backend@0.14.1 + +## 0.2.37 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.8.6 + - @backstage/plugin-scaffolder-backend@0.14.0 + - @backstage/plugin-catalog-backend@0.13.0 + - @backstage/plugin-auth-backend@0.3.17 + - @backstage/plugin-scaffolder-backend-module-rails@0.1.3 + - @backstage/plugin-search-backend-node@0.4.0 + - @backstage/plugin-techdocs-backend@0.8.7 + - @backstage/plugin-app-backend@0.3.15 + - @backstage/plugin-kubernetes-backend@0.3.10 + - @backstage/plugin-rollbar-backend@0.1.13 + - example-app@0.2.37 + - @backstage/plugin-search-backend@0.2.3 + +## 0.2.36 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@0.5.8 + - @backstage/plugin-scaffolder-backend@0.13.0 + - @backstage/catalog-model@0.9.0 + - @backstage/plugin-catalog-backend@0.12.0 + - @backstage/backend-common@0.8.5 + - @backstage/plugin-search-backend-node@0.3.0 + - example-app@0.2.36 + - @backstage/plugin-scaffolder-backend-module-rails@0.1.2 + - @backstage/catalog-client@0.3.16 + - @backstage/plugin-auth-backend@0.3.16 + - @backstage/plugin-badges-backend@0.1.8 + - @backstage/plugin-code-coverage-backend@0.1.8 + - @backstage/plugin-kafka-backend@0.2.8 + - @backstage/plugin-kubernetes-backend@0.3.9 + - @backstage/plugin-techdocs-backend@0.8.6 + - @backstage/plugin-todo-backend@0.1.8 + - @backstage/plugin-search-backend@0.2.2 + +## 0.2.35 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@0.12.4 + - @backstage/backend-common@0.8.4 + - @backstage/plugin-auth-backend@0.3.15 + - @backstage/plugin-catalog-backend@0.11.0 + - @backstage/plugin-techdocs-backend@0.8.5 + - @backstage/catalog-client@0.3.15 + - @backstage/plugin-kafka-backend@0.2.7 + +## 0.2.32 + +### Patch Changes + +- Updated dependencies [9c63be545] +- Updated dependencies [92963779b] +- Updated dependencies [27a9b503a] +- Updated dependencies [66c6bfebd] +- Updated dependencies [55a253de2] +- Updated dependencies [70bc30c5b] +- Updated dependencies [db1c8f93b] +- Updated dependencies [5aff84759] +- Updated dependencies [f26e6008f] +- Updated dependencies [eda9dbd5f] +- Updated dependencies [4f8cf50fe] +- Updated dependencies [875809a59] + - @backstage/plugin-catalog-backend@0.10.2 + - @backstage/backend-common@0.8.2 + - @backstage/catalog-model@0.8.2 + - @backstage/plugin-scaffolder-backend@0.12.0 + - @backstage/catalog-client@0.3.13 + - @backstage/plugin-search-backend-node@0.2.0 + - @backstage/plugin-search-backend@0.2.0 + - @backstage/plugin-proxy-backend@0.2.9 + - example-app@0.2.32 + +## 0.2.30 + +### Patch Changes + +- Updated dependencies [0fd4ea443] +- Updated dependencies [add62a455] +- Updated dependencies [260aaa684] +- Updated dependencies [704875e26] + - @backstage/plugin-catalog-backend@0.10.0 + - @backstage/catalog-client@0.3.12 + - @backstage/catalog-model@0.8.0 + - @backstage/plugin-scaffolder-backend@0.11.4 + - example-app@0.2.30 + - @backstage/plugin-auth-backend@0.3.12 + - @backstage/plugin-badges-backend@0.1.6 + - @backstage/plugin-code-coverage-backend@0.1.6 + - @backstage/plugin-kafka-backend@0.2.6 + - @backstage/plugin-kubernetes-backend@0.3.8 + - @backstage/plugin-techdocs-backend@0.8.2 + - @backstage/plugin-todo-backend@0.1.6 + +## 0.2.28 + +### Patch Changes + +- Updated dependencies [062bbf90f] +- Updated dependencies [22fd8ce2a] +- Updated dependencies [10c008a3a] +- Updated dependencies [82ca1ac22] +- Updated dependencies [f9fb4a205] +- Updated dependencies [9a207f052] +- Updated dependencies [16be1d093] +- Updated dependencies [fd39d4662] +- Updated dependencies [f9f9d633d] + - @backstage/plugin-scaffolder-backend@0.11.1 + - @backstage/backend-common@0.8.0 + - @backstage/catalog-model@0.7.9 + - @backstage/plugin-catalog-backend@0.9.0 + - @backstage/plugin-kubernetes-backend@0.3.7 + - example-app@0.2.28 + - @backstage/plugin-app-backend@0.3.13 + - @backstage/plugin-auth-backend@0.3.10 + - @backstage/plugin-badges-backend@0.1.4 + - @backstage/plugin-code-coverage-backend@0.1.5 + - @backstage/plugin-graphql-backend@0.1.8 + - @backstage/plugin-kafka-backend@0.2.5 + - @backstage/plugin-proxy-backend@0.2.8 + - @backstage/plugin-rollbar-backend@0.1.11 + - @backstage/plugin-search-backend@0.1.5 + - @backstage/plugin-techdocs-backend@0.8.1 + - @backstage/plugin-todo-backend@0.1.5 + +## 0.2.27 + +### Patch Changes + +- Updated dependencies [e0bfd3d44] +- Updated dependencies [e0bfd3d44] +- Updated dependencies [e0bfd3d44] +- Updated dependencies [38ca05168] +- Updated dependencies [b219821a0] +- Updated dependencies [69eefb5ae] +- Updated dependencies [f53fba29f] +- Updated dependencies [75c8cec39] +- Updated dependencies [227439a72] +- Updated dependencies [cdb3426e5] +- Updated dependencies [d8b81fd28] +- Updated dependencies [d1b1306d9] + - @backstage/plugin-scaffolder-backend@0.11.0 + - @backstage/backend-common@0.7.0 + - @backstage/plugin-techdocs-backend@0.8.0 + - @backstage/plugin-catalog-backend@0.8.2 + - @backstage/plugin-kubernetes-backend@0.3.6 + - @backstage/plugin-proxy-backend@0.2.7 + - @backstage/catalog-model@0.7.8 + - @backstage/config@0.1.5 + - @backstage/catalog-client@0.3.11 + - example-app@0.2.27 + - @backstage/plugin-app-backend@0.3.12 + - @backstage/plugin-auth-backend@0.3.9 + - @backstage/plugin-badges-backend@0.1.3 + - @backstage/plugin-code-coverage-backend@0.1.4 + - @backstage/plugin-graphql-backend@0.1.7 + - @backstage/plugin-kafka-backend@0.2.4 + - @backstage/plugin-rollbar-backend@0.1.10 + - @backstage/plugin-search-backend@0.1.4 + - @backstage/plugin-todo-backend@0.1.4 + +## 0.2.25 + +### Patch Changes + +- Updated dependencies [b9b2b4b76] +- Updated dependencies [84c54474d] +- Updated dependencies [49574a8a3] +- Updated dependencies [d367f63b5] +- Updated dependencies [5fe62f124] +- Updated dependencies [09b5fcf2e] +- Updated dependencies [55b2fc0c0] +- Updated dependencies [c42cd1daa] +- Updated dependencies [b42531cfe] +- Updated dependencies [c2306f898] + - @backstage/plugin-search-backend@0.1.3 + - @backstage/plugin-search-backend-node@0.1.3 + - @backstage/plugin-scaffolder-backend@0.10.0 + - @backstage/plugin-rollbar-backend@0.1.9 + - @backstage/backend-common@0.6.3 + - @backstage/plugin-catalog-backend@0.8.0 + - @backstage/plugin-code-coverage-backend@0.1.2 + - @backstage/plugin-kubernetes-backend@0.3.5 + - example-app@0.2.25 + +## 0.2.22 + +### Patch Changes + +- Updated dependencies [f03a52f5b] +- Updated dependencies [676ede643] +- Updated dependencies [1ac6a5233] +- Updated dependencies [2ab6f3ff0] +- Updated dependencies [0d55dcc74] +- Updated dependencies [29e1789e1] +- Updated dependencies [f1b2c1d2c] +- Updated dependencies [60e463c8d] +- Updated dependencies [676ede643] +- Updated dependencies [b196a4569] +- Updated dependencies [8488a1a96] +- Updated dependencies [37e3a69f5] +- Updated dependencies [6b2d54fd6] +- Updated dependencies [44590510d] +- Updated dependencies [164cc4c53] + - @backstage/plugin-kafka-backend@0.2.3 + - @backstage/plugin-catalog-backend@0.7.0 + - @backstage/plugin-kubernetes-backend@0.3.3 + - @backstage/plugin-scaffolder-backend@0.9.4 + - @backstage/plugin-auth-backend@0.3.7 + - @backstage/catalog-client@0.3.9 + - @backstage/plugin-todo-backend@0.1.3 + - @backstage/catalog-model@0.7.5 + - @backstage/backend-common@0.6.1 + +## 0.2.21 + +### Patch Changes + +- Updated dependencies [a2a3c7803] +- Updated dependencies [9f2e51e89] +- Updated dependencies [4d248725e] +- Updated dependencies [aaeb7ecf3] +- Updated dependencies [449776cd6] +- Updated dependencies [91e87c055] +- Updated dependencies [36d933ec5] +- Updated dependencies [113d3d59e] +- Updated dependencies [f47e11427] +- Updated dependencies [c862b3f36] + - @backstage/plugin-kubernetes-backend@0.3.2 + - @backstage/plugin-scaffolder-backend@0.9.3 + - @backstage/plugin-search-backend@0.1.2 + - @backstage/plugin-search-backend-node@0.1.2 + - @backstage/plugin-techdocs-backend@0.7.0 + - @backstage/plugin-auth-backend@0.3.6 + - @backstage/plugin-todo-backend@0.1.2 + - @backstage/plugin-catalog-backend@0.6.7 + - example-app@0.2.21 + +## 0.2.20 + +### Patch Changes + +- Updated dependencies [010aed784] +- Updated dependencies [8686eb38c] +- Updated dependencies [e7baa0d2e] +- Updated dependencies [8b4f7e42a] +- Updated dependencies [8686eb38c] +- Updated dependencies [0434853a5] +- Updated dependencies [4bc98a5b9] +- Updated dependencies [d2f4efc5d] +- Updated dependencies [8686eb38c] +- Updated dependencies [424742dc1] +- Updated dependencies [1f98a6ff8] +- Updated dependencies [8b5e59750] +- Updated dependencies [8686eb38c] + - @backstage/plugin-catalog-backend@0.6.6 + - @backstage/catalog-client@0.3.8 + - @backstage/plugin-techdocs-backend@0.6.5 + - @backstage/plugin-scaffolder-backend@0.9.2 + - @backstage/backend-common@0.6.0 + - @backstage/config@0.1.4 + - @backstage/plugin-auth-backend@0.3.5 + - @backstage/plugin-kubernetes-backend@0.3.1 + - example-app@0.2.20 + - @backstage/plugin-app-backend@0.3.10 + - @backstage/plugin-graphql-backend@0.1.6 + - @backstage/plugin-kafka-backend@0.2.2 + - @backstage/plugin-proxy-backend@0.2.6 + - @backstage/plugin-rollbar-backend@0.1.8 + - @backstage/plugin-todo-backend@0.1.1 + +## 0.2.19 + +### Patch Changes + +- Updated dependencies [5d7834baf] +- Updated dependencies [9ef5a126d] +- Updated dependencies [d7245b733] +- Updated dependencies [393b623ae] +- Updated dependencies [d7245b733] +- Updated dependencies [0b42fff22] +- Updated dependencies [0b42fff22] +- Updated dependencies [2ef5bc7ea] +- Updated dependencies [c532c1682] +- Updated dependencies [761698831] +- Updated dependencies [aa095e469] +- Updated dependencies [761698831] +- Updated dependencies [f98f212e4] +- Updated dependencies [9581ff0b4] +- Updated dependencies [93c62c755] +- Updated dependencies [02d78290a] +- Updated dependencies [a501128db] +- Updated dependencies [8de9963f0] +- Updated dependencies [5f1b7ea35] +- Updated dependencies [2e57922de] +- Updated dependencies [e2c1b3fb6] + - @backstage/plugin-kubernetes-backend@0.3.0 + - @backstage/plugin-catalog-backend@0.6.5 + - @backstage/backend-common@0.5.6 + - @backstage/plugin-app-backend@0.3.9 + - @backstage/plugin-scaffolder-backend@0.9.1 + - @backstage/catalog-model@0.7.4 + - @backstage/catalog-client@0.3.7 + - @backstage/plugin-techdocs-backend@0.6.4 + - @backstage/plugin-auth-backend@0.3.4 + - example-app@0.2.19 + +## 0.2.18 + +### Patch Changes + +- Updated dependencies [12d8f27a6] +- Updated dependencies [52b5bc3e2] +- Updated dependencies [ecdd407b1] +- Updated dependencies [4fbc9df79] +- Updated dependencies [12d8f27a6] +- Updated dependencies [497859088] +- Updated dependencies [1987c9341] +- Updated dependencies [f31b76b44] +- Updated dependencies [15eee03bc] +- Updated dependencies [f43192207] +- Updated dependencies [8adb48df4] +- Updated dependencies [e3adec2bd] +- Updated dependencies [9ce68b677] +- Updated dependencies [8106c9528] +- Updated dependencies [d0ed25196] +- Updated dependencies [96ccc8f69] +- Updated dependencies [3af994c81] + - @backstage/plugin-scaffolder-backend@0.9.0 + - @backstage/plugin-techdocs-backend@0.6.3 + - @backstage/plugin-catalog-backend@0.6.4 + - @backstage/plugin-kafka-backend@0.2.1 + - @backstage/catalog-model@0.7.3 + - @backstage/backend-common@0.5.5 + - @backstage/plugin-proxy-backend@0.2.5 + - @backstage/plugin-auth-backend@0.3.3 + - @backstage/plugin-kubernetes-backend@0.2.8 + - example-app@0.2.18 + +## 0.2.17 + +### Patch Changes + +- Updated dependencies [a70af22a2] +- Updated dependencies [ec504e7b4] +- Updated dependencies [a5f42cf66] +- Updated dependencies [f37992797] +- Updated dependencies [bad21a085] +- Updated dependencies [1c06cb312] +- Updated dependencies [2499f6cde] +- Updated dependencies [a1f5e6545] + - @backstage/plugin-kubernetes-backend@0.2.7 + - @backstage/plugin-auth-backend@0.3.2 + - @backstage/plugin-scaffolder-backend@0.8.0 + - @backstage/plugin-techdocs-backend@0.6.2 + - @backstage/catalog-model@0.7.2 + - @backstage/plugin-app-backend@0.3.8 + - @backstage/plugin-catalog-backend@0.6.3 + - @backstage/config@0.1.3 + - example-app@0.2.17 + +## 0.2.15 + +### Patch Changes + +- Updated dependencies [1deb31141] +- Updated dependencies [6ed2b47d6] +- Updated dependencies [77ad0003a] +- Updated dependencies [d2441aee3] +- Updated dependencies [727f0deec] +- Updated dependencies [fb53eb7cb] +- Updated dependencies [07bafa248] +- Updated dependencies [ffffea8e6] +- Updated dependencies [f3fbfb452] +- Updated dependencies [615103a63] +- Updated dependencies [84364b35c] +- Updated dependencies [82b2c11b6] +- Updated dependencies [965e200c6] +- Updated dependencies [5a5163519] +- Updated dependencies [82b2c11b6] +- Updated dependencies [08142b256] +- Updated dependencies [08142b256] + - @backstage/plugin-auth-backend@0.3.0 + - @backstage/plugin-scaffolder-backend@0.7.0 + - @backstage/plugin-catalog-backend@0.6.1 + - @backstage/plugin-app-backend@0.3.7 + - example-app@0.2.15 + - @backstage/backend-common@0.5.3 + - @backstage/plugin-techdocs-backend@0.6.0 + +## 0.2.14 + +### Patch Changes + +- Updated dependencies [c777df180] +- Updated dependencies [2430ee7c2] +- Updated dependencies [3149bfe63] +- Updated dependencies [6e612ce25] +- Updated dependencies [e44925723] +- Updated dependencies [9d6ef14bc] +- Updated dependencies [a26668913] +- Updated dependencies [025e122c3] +- Updated dependencies [e9aab60c7] +- Updated dependencies [24e47ef1e] +- Updated dependencies [7881f2117] +- Updated dependencies [529d16d27] +- Updated dependencies [cdea0baf1] +- Updated dependencies [11cb5ef94] + - @backstage/plugin-techdocs-backend@0.5.5 + - @backstage/backend-common@0.5.2 + - @backstage/plugin-catalog-backend@0.6.0 + - @backstage/catalog-model@0.7.1 + - example-app@0.2.14 + - @backstage/plugin-scaffolder-backend@0.6.0 + - @backstage/plugin-app-backend@0.3.6 + +## 0.2.13 + +### Patch Changes + +- Updated dependencies [26a3a6cf0] +- Updated dependencies [681111228] +- Updated dependencies [664dd08c9] +- Updated dependencies [9dd057662] +- Updated dependencies [234e7d985] +- Updated dependencies [d7b1d317f] +- Updated dependencies [a91aa6bf2] +- Updated dependencies [39b05b9ae] +- Updated dependencies [4eaa06057] + - @backstage/backend-common@0.5.1 + - @backstage/plugin-scaffolder-backend@0.5.2 + - @backstage/plugin-kubernetes-backend@0.2.6 + - @backstage/plugin-catalog-backend@0.5.5 + - @backstage/plugin-kafka-backend@0.2.0 + - @backstage/plugin-auth-backend@0.2.12 + - example-app@0.2.13 + - @backstage/plugin-app-backend@0.3.5 + +## 0.2.12 + +### Patch Changes + +- Updated dependencies [def2307f3] +- Updated dependencies [d54857099] +- Updated dependencies [0b135e7e0] +- Updated dependencies [318a6af9f] +- Updated dependencies [294a70cab] +- Updated dependencies [ac7be581a] +- Updated dependencies [0ea032763] +- Updated dependencies [5345a1f98] +- Updated dependencies [ed6baab66] +- Updated dependencies [ad838c02f] +- Updated dependencies [a5e27d5c1] +- Updated dependencies [0643a3336] +- Updated dependencies [a2291d7cc] +- Updated dependencies [f9ba00a1c] +- Updated dependencies [09a370426] +- Updated dependencies [a93f42213] + - @backstage/catalog-model@0.7.0 + - @backstage/plugin-catalog-backend@0.5.4 + - @backstage/plugin-kubernetes-backend@0.2.5 + - @backstage/backend-common@0.5.0 + - @backstage/plugin-scaffolder-backend@0.5.0 + - @backstage/plugin-techdocs-backend@0.5.4 + - @backstage/plugin-auth-backend@0.2.11 + - example-app@0.2.12 + - @backstage/plugin-kafka-backend@0.1.1 + - @backstage/plugin-app-backend@0.3.4 + - @backstage/plugin-graphql-backend@0.1.5 + - @backstage/plugin-proxy-backend@0.2.4 + - @backstage/plugin-rollbar-backend@0.1.7 + +## 0.2.11 + +### Patch Changes + +- cc068c0d6: Bump the gitbeaker dependencies to 28.x. + + To update your own installation, go through the `package.json` files of all of + your packages, and ensure that all dependencies on `@gitbeaker/node` or + `@gitbeaker/core` are at version `^28.0.2`. Then run `yarn install` at the root + of your repo. + +- Updated dependencies [68ad5af51] +- Updated dependencies [5a9a7e7c2] +- Updated dependencies [f3b064e1c] +- Updated dependencies [94fdf4955] +- Updated dependencies [cc068c0d6] +- Updated dependencies [ade6b3bdf] +- Updated dependencies [468579734] +- Updated dependencies [cb7af51e7] +- Updated dependencies [abbee6fff] +- Updated dependencies [147fadcb9] +- Updated dependencies [711ba55a2] + - @backstage/plugin-techdocs-backend@0.5.3 + - @backstage/plugin-kubernetes-backend@0.2.4 + - @backstage/catalog-model@0.6.1 + - @backstage/plugin-catalog-backend@0.5.3 + - @backstage/plugin-scaffolder-backend@0.4.1 + - @backstage/plugin-auth-backend@0.2.10 + - @backstage/backend-common@0.4.3 + +## 0.2.10 + +### Patch Changes + +- Updated dependencies [5eb8c9b9e] +- Updated dependencies [7e3451700] + - @backstage/plugin-scaffolder-backend@0.4.0 + +## 0.2.8 + +### Patch Changes + +- 7cfcd58ee: use node 14 for backend Dockerfile +- Updated dependencies [19554f6d6] +- Updated dependencies [33a82a713] +- Updated dependencies [5de26b9a6] +- Updated dependencies [30d6c78fb] +- Updated dependencies [5084e5039] +- Updated dependencies [a8573e53b] +- Updated dependencies [aed8f7f12] + - @backstage/plugin-scaffolder-backend@0.3.6 + - @backstage/plugin-catalog-backend@0.5.1 + - @backstage/plugin-techdocs-backend@0.5.0 + - example-app@0.2.8 + +## 0.2.7 + +### Patch Changes + +- Updated dependencies [c6eeefa35] +- Updated dependencies [fb386b760] +- Updated dependencies [c911061b7] +- Updated dependencies [7c3ffc0cd] +- Updated dependencies [dae4f3983] +- Updated dependencies [7b15cc271] +- Updated dependencies [e7496dc3e] +- Updated dependencies [1d1c2860f] +- Updated dependencies [0e6298f7e] +- Updated dependencies [8dd0a906d] +- Updated dependencies [4eafdec4a] +- Updated dependencies [6b37c95bf] +- Updated dependencies [8c31c681c] +- Updated dependencies [7b98e7fee] +- Updated dependencies [ac3560b42] +- Updated dependencies [94c65a9d4] +- Updated dependencies [0097057ed] + - @backstage/plugin-catalog-backend@0.5.0 + - @backstage/catalog-model@0.6.0 + - @backstage/plugin-techdocs-backend@0.4.0 + - @backstage/plugin-auth-backend@0.2.7 + - @backstage/backend-common@0.4.1 + - @backstage/plugin-scaffolder-backend@0.3.5 + - example-app@0.2.7 + - @backstage/plugin-kubernetes-backend@0.2.3 + +## 0.2.6 + +### Patch Changes + +- 1e22f8e0b: Unify `dockerode` library and type dependency versions +- Updated dependencies [6e8bb3ac0] +- Updated dependencies [e708679d7] +- Updated dependencies [047c018c9] +- Updated dependencies [38e24db00] +- Updated dependencies [e3bd9fc2f] +- Updated dependencies [12bbd748c] +- Updated dependencies [38d63fbe1] +- Updated dependencies [1e22f8e0b] +- Updated dependencies [83b6e0c1f] +- Updated dependencies [e3bd9fc2f] + - @backstage/plugin-catalog-backend@0.4.0 + - @backstage/backend-common@0.4.0 + - @backstage/config@0.1.2 + - @backstage/plugin-scaffolder-backend@0.3.4 + - @backstage/plugin-techdocs-backend@0.3.2 + - @backstage/catalog-model@0.5.0 + - example-app@0.2.6 + - @backstage/plugin-app-backend@0.3.3 + - @backstage/plugin-auth-backend@0.2.6 + - @backstage/plugin-graphql-backend@0.1.4 + - @backstage/plugin-kubernetes-backend@0.2.2 + - @backstage/plugin-proxy-backend@0.2.3 + - @backstage/plugin-rollbar-backend@0.1.5 + +## 0.2.5 + +### Patch Changes + +- Updated dependencies [ae95c7ff3] +- Updated dependencies [b4488ddb0] +- Updated dependencies [612368274] +- Updated dependencies [6a6c7c14e] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [e42402b47] +- Updated dependencies [bcc211a08] +- Updated dependencies [3619ea4c4] + - @backstage/plugin-techdocs-backend@0.3.1 + - @backstage/plugin-catalog-backend@0.3.0 + - @backstage/backend-common@0.3.3 + - @backstage/plugin-proxy-backend@0.2.2 + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-kubernetes-backend@0.2.1 + - @backstage/plugin-app-backend@0.3.2 + - example-app@0.2.5 + - @backstage/plugin-auth-backend@0.2.5 + - @backstage/plugin-scaffolder-backend@0.3.3 + +## 0.2.4 + +### Patch Changes + +- Updated dependencies [50eff1d00] +- Updated dependencies [ff1301d28] +- Updated dependencies [4b53294a6] +- Updated dependencies [3aa7efb3f] +- Updated dependencies [1ec19a3f4] +- Updated dependencies [ab94c9542] +- Updated dependencies [3a201c5d5] +- Updated dependencies [2daf18e80] +- Updated dependencies [069cda35f] +- Updated dependencies [b3d4e4e57] +- Updated dependencies [700a212b4] + - @backstage/plugin-auth-backend@0.2.4 + - @backstage/plugin-app-backend@0.3.1 + - @backstage/plugin-techdocs-backend@0.3.0 + - @backstage/backend-common@0.3.2 + - @backstage/plugin-catalog-backend@0.2.3 + - @backstage/catalog-model@0.3.1 + - @backstage/plugin-rollbar-backend@0.1.4 + - example-app@0.2.4 + +## 0.2.3 + +### Patch Changes + +- Updated dependencies [1166fcc36] +- Updated dependencies [bff3305aa] +- Updated dependencies [0c2121240] +- Updated dependencies [ef2831dde] +- Updated dependencies [1185919f3] +- Updated dependencies [475fc0aaa] +- Updated dependencies [b47dce06f] +- Updated dependencies [5a1d8dca3] + - @backstage/catalog-model@0.3.0 + - @backstage/plugin-kubernetes-backend@0.2.0 + - @backstage/backend-common@0.3.1 + - @backstage/plugin-catalog-backend@0.2.2 + - @backstage/plugin-scaffolder-backend@0.3.2 + - example-app@0.2.3 + - @backstage/plugin-auth-backend@0.2.3 + - @backstage/plugin-techdocs-backend@0.2.2 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies [1722cb53c] +- Updated dependencies [1722cb53c] +- Updated dependencies [1722cb53c] +- Updated dependencies [f531d307c] +- Updated dependencies [3efd03c0e] +- Updated dependencies [7b37e6834] +- Updated dependencies [8e2effb53] +- Updated dependencies [d33f5157c] + - @backstage/backend-common@0.3.0 + - @backstage/plugin-app-backend@0.3.0 + - @backstage/plugin-catalog-backend@0.2.1 + - example-app@0.2.2 + - @backstage/plugin-scaffolder-backend@0.3.1 + - @backstage/plugin-auth-backend@0.2.2 + - @backstage/plugin-graphql-backend@0.1.3 + - @backstage/plugin-kubernetes-backend@0.1.3 + - @backstage/plugin-proxy-backend@0.2.1 + - @backstage/plugin-rollbar-backend@0.1.3 + - @backstage/plugin-sentry-backend@0.1.3 + - @backstage/plugin-techdocs-backend@0.2.1 + +## 0.2.1 + +### Patch Changes + +- Updated dependencies [752808090] +- Updated dependencies [462876399] +- Updated dependencies [59166e5ec] +- Updated dependencies [33b7300eb] + - @backstage/plugin-auth-backend@0.2.1 + - @backstage/plugin-scaffolder-backend@0.3.0 + - @backstage/backend-common@0.2.1 + - example-app@0.2.1 + +## 0.2.0 + +### Patch Changes + +- 440a17b39: Bump @backstage/catalog-backend and pass the now required UrlReader interface to the plugin +- 6840a68df: Pass GitHub token into Scaffolder GitHub Preparer +- 8c2b76e45: **BREAKING CHANGE** + + The existing loading of additional config files like `app-config.development.yaml` using APP_ENV or NODE_ENV has been removed. + Instead, the CLI and backend process now accept one or more `--config` flags to load config files. + + Without passing any flags, `app-config.yaml` and, if it exists, `app-config.local.yaml` will be loaded. + If passing any `--config ` flags, only those files will be loaded, **NOT** the default `app-config.yaml` one. + + The old behaviour of for example `APP_ENV=development` can be replicated using the following flags: + + ```bash + --config ../../app-config.yaml --config ../../app-config.development.yaml + ``` + +- 7bbeb049f: Change loadBackendConfig to return the config directly +- Updated dependencies [28edd7d29] +- Updated dependencies [819a70229] +- Updated dependencies [3a4236570] +- Updated dependencies [3e254503d] +- Updated dependencies [6d29605db] +- Updated dependencies [e0be86b6f] +- Updated dependencies [f70a52868] +- Updated dependencies [12b5fe940] +- Updated dependencies [5249594c5] +- Updated dependencies [56e4eb589] +- Updated dependencies [b4e5466e1] +- Updated dependencies [6f1768c0f] +- Updated dependencies [e37c0a005] +- Updated dependencies [3472c8be7] +- Updated dependencies [57d555eb2] +- Updated dependencies [61db1ddc6] +- Updated dependencies [81cb94379] +- Updated dependencies [1687b8fbb] +- Updated dependencies [a768a07fb] +- Updated dependencies [a768a07fb] +- Updated dependencies [f00ca3cb8] +- Updated dependencies [0c370c979] +- Updated dependencies [ce1f55398] +- Updated dependencies [e6b00e3af] +- Updated dependencies [9226c2aaa] +- Updated dependencies [6d97d2d6f] +- Updated dependencies [99710b102] +- Updated dependencies [6579769df] +- Updated dependencies [002860e7a] +- Updated dependencies [5adfc005e] +- Updated dependencies [33454c0f2] +- Updated dependencies [183e2a30d] +- Updated dependencies [948052cbb] +- Updated dependencies [65d722455] +- Updated dependencies [b652bf2cc] +- Updated dependencies [4036ff59d] +- Updated dependencies [991a950e0] +- Updated dependencies [512d70973] +- Updated dependencies [8c2b76e45] +- Updated dependencies [8bdf0bcf5] +- Updated dependencies [c926765a2] +- Updated dependencies [5a920c6e4] +- Updated dependencies [2f62e1804] +- Updated dependencies [440a17b39] +- Updated dependencies [fa56f4615] +- Updated dependencies [8afce088a] +- Updated dependencies [4c4eab81b] +- Updated dependencies [22ff8fba5] +- Updated dependencies [36a71d278] +- Updated dependencies [b3d57961c] +- Updated dependencies [6840a68df] +- Updated dependencies [a5cb46bac] +- Updated dependencies [49d70ccab] +- Updated dependencies [1c8c43756] +- Updated dependencies [26e69ab1a] +- Updated dependencies [5e4551e3a] +- Updated dependencies [e142a2767] +- Updated dependencies [e7f5471fd] +- Updated dependencies [e3d063ffa] +- Updated dependencies [440a17b39] +- Updated dependencies [7bbeb049f] + - @backstage/plugin-app-backend@0.2.0 + - @backstage/plugin-auth-backend@0.2.0 + - @backstage/catalog-model@0.2.0 + - @backstage/plugin-scaffolder-backend@0.2.0 + - @backstage/plugin-techdocs-backend@0.2.0 + - @backstage/plugin-catalog-backend@0.2.0 + - @backstage/plugin-proxy-backend@0.2.0 + - @backstage/backend-common@0.2.0 + - example-app@0.2.0 + - @backstage/plugin-graphql-backend@0.1.2 + - @backstage/plugin-kubernetes-backend@0.1.2 + - @backstage/plugin-rollbar-backend@0.1.2 + - @backstage/plugin-sentry-backend@0.1.2 diff --git a/packages/backend-legacy/README.md b/packages/backend-legacy/README.md new file mode 100644 index 0000000000..0de555fe70 --- /dev/null +++ b/packages/backend-legacy/README.md @@ -0,0 +1,61 @@ +# example-backend-legacy + +This package is an EXAMPLE of a Backstage backend using the old backend system. + +The main purpose of this package is to provide a test bed for Backstage plugins +that have a backend part. Feel free to experiment locally or within your fork +by adding dependencies and routes to this backend, to try things out. + +By running the `@backstage/create-app` script, you get your own separate Backstage backend. + +## Development + +To run the example backend, first go to the project root and run + +```bash +yarn install +``` + +You should only need to do this once. + +After that, go to the `packages/backend-legacy` directory and run + +```bash +yarn start +``` + +If you want to override any configuration locally, for example adding any secrets, +you can do so in `app-config.local.yaml`. + +The backend starts up on port 7007 per default. + +### Debugging + +The backend is a node process that can be inspected to allow breakpoints and live debugging. To enable this, pass the `--inspect` flag to [backend:dev](https://backstage.io/docs/tooling/cli/build-system#backend-development). + +To debug the backend in [Visual Studio Code](https://code.visualstudio.com/): + +- Enable Auto Attach (⌘ + Shift + P > Toggle Auto Attach > Only With Flag) +- Open a VSCode terminal (Control + `) +- Run the backend from the VSCode terminal: `yarn start-backend:legacy --inspect` + +## Populating The Catalog + +If you want to use the catalog functionality, you need to add so called +locations to the backend. These are places where the backend can find some +entity descriptor data to consume and serve. For more information, see +[Software Catalog Overview - Adding Components to the Catalog](https://backstage.io/docs/features/software-catalog/#adding-components-to-the-catalog). + +For convenience we already include some statically configured example locations +in `app-config.yaml` under `catalog.locations`. For local development you can override these in your own `app-config.local.yaml`. + +## Authentication + +We chose [Passport](http://www.passportjs.org/) as authentication platform due to its comprehensive set of supported authentication [strategies](http://www.passportjs.org/packages/). + +Read more about the [auth-backend](https://github.com/backstage/backstage/blob/master/plugins/auth-backend/README.md) and [how to add a new provider](https://github.com/backstage/backstage/blob/master/docs/auth/add-auth-provider.md) + +## Documentation + +- [Backstage Readme](https://github.com/backstage/backstage/blob/master/README.md) +- [Backstage Documentation](https://backstage.io/docs) diff --git a/packages/backend-next/catalog-info.yaml b/packages/backend-legacy/catalog-info.yaml similarity index 68% rename from packages/backend-next/catalog-info.yaml rename to packages/backend-legacy/catalog-info.yaml index d297365e4b..a0acd6c653 100644 --- a/packages/backend-next/catalog-info.yaml +++ b/packages/backend-legacy/catalog-info.yaml @@ -1,8 +1,8 @@ apiVersion: backstage.io/v1alpha1 kind: Component metadata: - name: example-backend-next - title: example-backend-next + name: example-backend-legacy + title: example-backend-legacy spec: lifecycle: experimental type: backstage-backend diff --git a/packages/backend-legacy/knip-report.md b/packages/backend-legacy/knip-report.md new file mode 100644 index 0000000000..f57bda79b7 --- /dev/null +++ b/packages/backend-legacy/knip-report.md @@ -0,0 +1,27 @@ +# Knip report + +## Unused dependencies (13) + +| Name | Location | Severity | +| :------------------------------------------------- | :----------- | :------- | +| @backstage/plugin-scaffolder-backend-module-gitlab | package.json | error | +| @backstage/plugin-scaffolder-backend-module-rails | package.json | error | +| @backstage/plugin-azure-sites-common | package.json | error | +| @backstage/plugin-tech-insights-node | package.json | error | +| azure-devops-node-api | package.json | error | +| pg-connection-string | package.json | error | +| @gitbeaker/node | package.json | error | +| better-sqlite3 | package.json | error | +| @octokit/rest | package.json | error | +| example-app | package.json | error | +| mysql2 | package.json | error | +| luxon | package.json | error | +| pg | package.json | error | + +## Unused devDependencies (2) + +| Name | Location | Severity | +| :------------------------------- | :----------- | :------- | +| @types/express-serve-static-core | package.json | error | +| @types/luxon | package.json | error | + diff --git a/packages/backend-next/package.json b/packages/backend-legacy/package.json similarity index 54% rename from packages/backend-next/package.json rename to packages/backend-legacy/package.json index 65416da7a3..abdf3cb500 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-legacy/package.json @@ -1,21 +1,24 @@ { - "name": "example-backend-next", - "version": "0.0.26-next.0", - "main": "dist/index.cjs.js", - "types": "src/index.ts", - "license": "Apache-2.0", - "private": true, + "name": "example-backend-legacy", + "version": "0.2.99-next.1", "backstage": { "role": "backend" }, + "private": true, + "keywords": [ + "backstage" + ], "homepage": "https://backstage.io", "repository": { "type": "git", "url": "https://github.com/backstage/backstage", - "directory": "packages/backend-next" + "directory": "packages/backend-legacy" }, - "keywords": [ - "backstage" + "license": "Apache-2.0", + "main": "dist/index.cjs.js", + "types": "src/index.ts", + "files": [ + "dist" ], "scripts": { "build": "backstage-cli package build", @@ -25,42 +28,62 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-defaults": "workspace:^", - "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-common": "workspace:^", "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/integration": "workspace:^", "@backstage/plugin-app-backend": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", - "@backstage/plugin-auth-backend-module-github-provider": "workspace:^", - "@backstage/plugin-auth-backend-module-guest-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "workspace:^", - "@backstage/plugin-catalog-backend-module-openapi": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^", + "@backstage/plugin-catalog-node": "workspace:^", "@backstage/plugin-devtools-backend": "workspace:^", + "@backstage/plugin-events-backend": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", "@backstage/plugin-kubernetes-backend": "workspace:^", - "@backstage/plugin-notifications-backend": "workspace:^", "@backstage/plugin-permission-backend": "workspace:^", - "@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", "@backstage/plugin-proxy-backend": "workspace:^", "@backstage/plugin-scaffolder-backend": "workspace:^", - "@backstage/plugin-scaffolder-backend-module-github": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-rails": "workspace:^", "@backstage/plugin-search-backend": "workspace:^", "@backstage/plugin-search-backend-module-catalog": "workspace:^", + "@backstage/plugin-search-backend-module-elasticsearch": "workspace:^", "@backstage/plugin-search-backend-module-explore": "workspace:^", + "@backstage/plugin-search-backend-module-pg": "workspace:^", "@backstage/plugin-search-backend-module-techdocs": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-signals-backend": "workspace:^", - "@backstage/plugin-techdocs-backend": "workspace:^" + "@backstage/plugin-signals-node": "workspace:^", + "@backstage/plugin-techdocs-backend": "workspace:^", + "@gitbeaker/node": "^35.1.0", + "@octokit/rest": "^19.0.3", + "azure-devops-node-api": "^12.0.0", + "better-sqlite3": "^9.0.0", + "dockerode": "^4.0.0", + "example-app": "link:../app", + "express": "^4.17.1", + "express-prom-bundle": "^7.0.0", + "express-promise-router": "^4.1.0", + "luxon": "^3.0.0", + "mysql2": "^3.0.0", + "pg": "^8.11.3", + "pg-connection-string": "^2.3.0", + "prom-client": "^15.0.0", + "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "workspace:^" - }, - "files": [ - "dist" - ] + "@backstage/cli": "workspace:^", + "@types/dockerode": "^3.3.0", + "@types/express": "^4.17.6", + "@types/express-serve-static-core": "^4.17.5", + "@types/luxon": "^3.0.0" + } } diff --git a/packages/backend/src/index.test.ts b/packages/backend-legacy/src/index.test.ts similarity index 100% rename from packages/backend/src/index.test.ts rename to packages/backend-legacy/src/index.test.ts diff --git a/packages/backend-legacy/src/index.ts b/packages/backend-legacy/src/index.ts new file mode 100644 index 0000000000..33520cba03 --- /dev/null +++ b/packages/backend-legacy/src/index.ts @@ -0,0 +1,173 @@ +/* + * 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. + */ + +/* + * Hi! + * + * Note that this is an EXAMPLE Backstage backend. Please check the README. + * + * Happy hacking! + */ + +import Router from 'express-promise-router'; +import { + CacheManager, + createServiceBuilder, + DatabaseManager, + getRootLogger, + HostDiscovery, + loadBackendConfig, + notFoundHandler, + ServerTokenManager, + UrlReaders, + useHotMemoize, +} from '@backstage/backend-common'; +import { TaskScheduler } from '@backstage/backend-tasks'; +import { Config } from '@backstage/config'; +import healthcheck from './plugins/healthcheck'; +import { metricsHandler, metricsInit } from './metrics'; +import auth from './plugins/auth'; +import catalog from './plugins/catalog'; +import events from './plugins/events'; +import kubernetes from './plugins/kubernetes'; +import scaffolder from './plugins/scaffolder'; +import proxy from './plugins/proxy'; +import search from './plugins/search'; +import techdocs from './plugins/techdocs'; +import app from './plugins/app'; +import permission from './plugins/permission'; +import signals from './plugins/signals'; +import devtools from './plugins/devtools'; +import { PluginEnvironment } from './types'; +import { ServerPermissionClient } from '@backstage/plugin-permission-node'; +import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; +import { DefaultEventBroker } from '@backstage/plugin-events-backend'; +import { DefaultEventsService } from '@backstage/plugin-events-node'; +import { DefaultSignalsService } from '@backstage/plugin-signals-node'; + +function makeCreateEnv(config: Config) { + const root = getRootLogger(); + const reader = UrlReaders.default({ logger: root, config }); + const discovery = HostDiscovery.fromConfig(config); + const tokenManager = ServerTokenManager.fromConfig(config, { logger: root }); + const permissions = ServerPermissionClient.fromConfig(config, { + discovery, + tokenManager, + }); + const databaseManager = DatabaseManager.fromConfig(config, { logger: root }); + const cacheManager = CacheManager.fromConfig(config); + const taskScheduler = TaskScheduler.fromConfig(config, { databaseManager }); + const identity = DefaultIdentityClient.create({ + discovery, + }); + + const eventsService = DefaultEventsService.create({ logger: root }); + const eventBroker = new DefaultEventBroker( + root.child({ type: 'plugin' }), + eventsService, + ); + const signalsService = DefaultSignalsService.create({ + events: eventsService, + }); + + root.info(`Created UrlReader ${reader}`); + + return (plugin: string): PluginEnvironment => { + const logger = root.child({ type: 'plugin', plugin }); + const database = databaseManager.forPlugin(plugin); + const cache = cacheManager.forPlugin(plugin); + const scheduler = taskScheduler.forPlugin(plugin); + + return { + logger, + cache, + database, + config, + reader, + eventBroker, + events: eventsService, + discovery, + tokenManager, + permissions, + scheduler, + identity, + signals: signalsService, + }; + }; +} + +async function main() { + metricsInit(); + const logger = getRootLogger(); + + logger.info( + `You are running an example backend, which is supposed to be mainly used for contributing back to Backstage. ` + + `Do NOT deploy this to production. Read more here https://backstage.io/docs/getting-started/`, + ); + + const config = await loadBackendConfig({ + argv: process.argv, + logger, + }); + + const createEnv = makeCreateEnv(config); + + const healthcheckEnv = useHotMemoize(module, () => createEnv('healthcheck')); + const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); + const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder')); + const authEnv = useHotMemoize(module, () => createEnv('auth')); + const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); + const searchEnv = useHotMemoize(module, () => createEnv('search')); + const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes')); + const appEnv = useHotMemoize(module, () => createEnv('app')); + const permissionEnv = useHotMemoize(module, () => createEnv('permission')); + const eventsEnv = useHotMemoize(module, () => createEnv('events')); + const devToolsEnv = useHotMemoize(module, () => createEnv('devtools')); + const signalsEnv = useHotMemoize(module, () => createEnv('signals')); + + const apiRouter = Router(); + apiRouter.use('/catalog', await catalog(catalogEnv)); + apiRouter.use('/events', await events(eventsEnv)); + apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)); + apiRouter.use('/auth', await auth(authEnv)); + apiRouter.use('/search', await search(searchEnv)); + apiRouter.use('/techdocs', await techdocs(techdocsEnv)); + apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv)); + apiRouter.use('/proxy', await proxy(proxyEnv)); + apiRouter.use('/permission', await permission(permissionEnv)); + apiRouter.use('/devtools', await devtools(devToolsEnv)); + apiRouter.use('/signals', await signals(signalsEnv)); + apiRouter.use(notFoundHandler()); + + const service = createServiceBuilder(module) + .loadConfig(config) + .addRouter('', await healthcheck(healthcheckEnv)) + .addRouter('', metricsHandler()) + .addRouter('/api', apiRouter) + .addRouter('', await app(appEnv)); + + await service.start().catch(err => { + logger.error(err); + process.exit(1); + }); +} + +module.hot?.accept(); +main().catch(error => { + console.error('Backend failed to start up', error); + process.exit(1); +}); diff --git a/packages/backend/src/metrics.ts b/packages/backend-legacy/src/metrics.ts similarity index 100% rename from packages/backend/src/metrics.ts rename to packages/backend-legacy/src/metrics.ts diff --git a/packages/backend/src/plugins/DemoEventBasedEntityProvider.ts b/packages/backend-legacy/src/plugins/DemoEventBasedEntityProvider.ts similarity index 100% rename from packages/backend/src/plugins/DemoEventBasedEntityProvider.ts rename to packages/backend-legacy/src/plugins/DemoEventBasedEntityProvider.ts diff --git a/packages/backend/src/plugins/app.ts b/packages/backend-legacy/src/plugins/app.ts similarity index 100% rename from packages/backend/src/plugins/app.ts rename to packages/backend-legacy/src/plugins/app.ts diff --git a/packages/backend/src/plugins/auth.ts b/packages/backend-legacy/src/plugins/auth.ts similarity index 100% rename from packages/backend/src/plugins/auth.ts rename to packages/backend-legacy/src/plugins/auth.ts diff --git a/packages/backend/src/plugins/catalog.ts b/packages/backend-legacy/src/plugins/catalog.ts similarity index 100% rename from packages/backend/src/plugins/catalog.ts rename to packages/backend-legacy/src/plugins/catalog.ts diff --git a/packages/backend/src/plugins/devtools.ts b/packages/backend-legacy/src/plugins/devtools.ts similarity index 100% rename from packages/backend/src/plugins/devtools.ts rename to packages/backend-legacy/src/plugins/devtools.ts diff --git a/packages/backend/src/plugins/events.ts b/packages/backend-legacy/src/plugins/events.ts similarity index 100% rename from packages/backend/src/plugins/events.ts rename to packages/backend-legacy/src/plugins/events.ts diff --git a/packages/backend/src/plugins/healthcheck.ts b/packages/backend-legacy/src/plugins/healthcheck.ts similarity index 100% rename from packages/backend/src/plugins/healthcheck.ts rename to packages/backend-legacy/src/plugins/healthcheck.ts diff --git a/packages/backend/src/plugins/kubernetes.ts b/packages/backend-legacy/src/plugins/kubernetes.ts similarity index 100% rename from packages/backend/src/plugins/kubernetes.ts rename to packages/backend-legacy/src/plugins/kubernetes.ts diff --git a/packages/backend/src/plugins/permission.ts b/packages/backend-legacy/src/plugins/permission.ts similarity index 100% rename from packages/backend/src/plugins/permission.ts rename to packages/backend-legacy/src/plugins/permission.ts diff --git a/packages/backend/src/plugins/proxy.ts b/packages/backend-legacy/src/plugins/proxy.ts similarity index 100% rename from packages/backend/src/plugins/proxy.ts rename to packages/backend-legacy/src/plugins/proxy.ts diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend-legacy/src/plugins/scaffolder.ts similarity index 100% rename from packages/backend/src/plugins/scaffolder.ts rename to packages/backend-legacy/src/plugins/scaffolder.ts diff --git a/packages/backend/src/plugins/search.ts b/packages/backend-legacy/src/plugins/search.ts similarity index 100% rename from packages/backend/src/plugins/search.ts rename to packages/backend-legacy/src/plugins/search.ts diff --git a/packages/backend/src/plugins/signals.ts b/packages/backend-legacy/src/plugins/signals.ts similarity index 97% rename from packages/backend/src/plugins/signals.ts rename to packages/backend-legacy/src/plugins/signals.ts index d97d3fc170..33b1af5edf 100644 --- a/packages/backend/src/plugins/signals.ts +++ b/packages/backend-legacy/src/plugins/signals.ts @@ -25,5 +25,6 @@ export default async function createPlugin( events: env.events, identity: env.identity, discovery: env.discovery, + config: env.config, }); } diff --git a/packages/backend/src/plugins/techdocs.ts b/packages/backend-legacy/src/plugins/techdocs.ts similarity index 100% rename from packages/backend/src/plugins/techdocs.ts rename to packages/backend-legacy/src/plugins/techdocs.ts diff --git a/packages/backend/src/types.ts b/packages/backend-legacy/src/types.ts similarity index 100% rename from packages/backend/src/types.ts rename to packages/backend-legacy/src/types.ts diff --git a/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md deleted file mode 100644 index 3c48343ee4..0000000000 --- a/packages/backend-next/CHANGELOG.md +++ /dev/null @@ -1,2365 +0,0 @@ -# example-backend-next - -## 0.0.26-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.0 - - @backstage/plugin-catalog-backend@1.22.0-next.0 - - @backstage/plugin-scaffolder-backend@1.22.5-next.0 - - @backstage/catalog-model@1.5.0-next.0 - - @backstage/plugin-search-backend-node@1.2.22-next.0 - - @backstage/plugin-search-backend@1.5.8-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.23-next.0 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1-next.0 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.4-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.23-next.0 - - @backstage/plugin-auth-backend@0.22.5-next.0 - - @backstage/plugin-auth-node@0.4.13-next.0 - - @backstage/plugin-notifications-backend@0.2.1-next.0 - - @backstage/backend-plugin-api@0.6.18-next.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.36-next.0 - - @backstage/backend-defaults@0.2.18-next.0 - - @backstage/plugin-app-backend@0.3.66-next.0 - - @backstage/plugin-kubernetes-backend@0.17.1-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.0 - - @backstage/plugin-techdocs-backend@1.10.5-next.0 - - @backstage/backend-tasks@0.5.23-next.0 - - @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.0 - - @backstage/plugin-devtools-backend@0.3.4-next.0 - - @backstage/plugin-permission-backend@0.5.42-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15-next.0 - - @backstage/plugin-permission-common@0.7.13 - - @backstage/plugin-permission-node@0.7.29-next.0 - - @backstage/plugin-proxy-backend@0.4.16-next.0 - - @backstage/plugin-signals-backend@0.1.4-next.0 - -## 0.0.25 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-badges-backend@0.4.0 - - @backstage/plugin-kubernetes-backend@0.17.0 - - @backstage/plugin-azure-devops-backend@0.6.4 - - @backstage/plugin-techdocs-backend@1.10.4 - - @backstage/plugin-notifications-backend@0.2.0 - - @backstage/plugin-permission-node@0.7.28 - - @backstage/plugin-auth-backend@0.22.4 - - @backstage/plugin-catalog-backend@1.21.1 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.0 - - @backstage/backend-plugin-api@0.6.17 - - @backstage/plugin-search-backend@1.5.7 - - @backstage/plugin-todo-backend@0.3.16 - - @backstage/plugin-scaffolder-backend-module-github@0.2.7 - - @backstage/plugin-search-backend-module-techdocs@0.1.22 - - @backstage/plugin-search-backend-module-explore@0.1.21 - - @backstage/plugin-entity-feedback-backend@0.2.14 - - @backstage/plugin-search-backend-node@1.2.21 - - @backstage/plugin-lighthouse-backend@0.4.10 - - @backstage/plugin-permission-backend@0.5.41 - - @backstage/plugin-sonarqube-backend@0.2.19 - - @backstage/plugin-devtools-backend@0.3.3 - - @backstage/plugin-linguist-backend@0.5.15 - - @backstage/plugin-playlist-backend@0.3.21 - - @backstage/plugin-jenkins-backend@0.4.4 - - @backstage/backend-tasks@0.5.22 - - @backstage/plugin-nomad-backend@0.1.19 - - @backstage/plugin-adr-backend@0.4.14 - - @backstage/plugin-app-backend@0.3.65 - - @backstage/plugin-auth-node@0.4.12 - - @backstage/plugin-signals-backend@0.1.3 - - @backstage/plugin-proxy-backend@0.4.15 - - @backstage/plugin-scaffolder-backend@1.22.4 - - @backstage/backend-defaults@0.2.17 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.3 - - @backstage/plugin-catalog-backend-module-openapi@0.1.35 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4 - - @backstage/plugin-search-backend-module-catalog@0.1.22 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.14 - - @backstage/catalog-model@1.4.5 - - @backstage/plugin-auth-backend-module-github-provider@0.1.14 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15 - - @backstage/plugin-permission-common@0.7.13 - -## 0.0.25-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.17.0-next.1 - - @backstage/plugin-azure-devops-backend@0.6.4-next.1 - - @backstage/plugin-techdocs-backend@1.10.4-next.1 - - @backstage/plugin-auth-backend@0.22.4-next.1 - - @backstage/backend-plugin-api@0.6.17-next.1 - - @backstage/plugin-auth-node@0.4.12-next.1 - - @backstage/plugin-proxy-backend@0.4.15-next.1 - - @backstage/plugin-scaffolder-backend@1.22.4-next.1 - - @backstage/plugin-catalog-backend@1.21.1-next.1 - - @backstage/plugin-scaffolder-backend-module-github@0.2.7-next.1 - - @backstage/plugin-app-backend@0.3.65-next.1 - - @backstage/plugin-notifications-backend@0.2.0-next.1 - - @backstage/backend-defaults@0.2.17-next.1 - - @backstage/backend-tasks@0.5.22-next.1 - - @backstage/plugin-adr-backend@0.4.14-next.1 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.3-next.1 - - @backstage/plugin-badges-backend@0.3.14-next.1 - - @backstage/plugin-catalog-backend-module-openapi@0.1.35-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4-next.1 - - @backstage/plugin-devtools-backend@0.3.3-next.1 - - @backstage/plugin-entity-feedback-backend@0.2.14-next.1 - - @backstage/plugin-jenkins-backend@0.4.4-next.1 - - @backstage/plugin-lighthouse-backend@0.4.10-next.1 - - @backstage/plugin-linguist-backend@0.5.15-next.1 - - @backstage/plugin-nomad-backend@0.1.19-next.1 - - @backstage/plugin-permission-backend@0.5.41-next.1 - - @backstage/plugin-permission-node@0.7.28-next.1 - - @backstage/plugin-playlist-backend@0.3.21-next.1 - - @backstage/plugin-search-backend@1.5.7-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.22-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.21-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.22-next.1 - - @backstage/plugin-search-backend-node@1.2.21-next.1 - - @backstage/plugin-signals-backend@0.1.3-next.1 - - @backstage/plugin-sonarqube-backend@0.2.19-next.1 - - @backstage/plugin-todo-backend@0.3.16-next.1 - - @backstage/catalog-model@1.4.5 - - @backstage/plugin-auth-backend-module-github-provider@0.1.14-next.1 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.11-next.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15-next.1 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.14-next.1 - - @backstage/plugin-permission-common@0.7.13 - -## 0.0.25-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-techdocs-backend@1.10.4-next.0 - - @backstage/plugin-catalog-backend@1.21.1-next.0 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.11-next.0 - - @backstage/plugin-kubernetes-backend@0.16.4-next.0 - - @backstage/plugin-signals-backend@0.1.3-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.22-next.0 - - @backstage/plugin-scaffolder-backend@1.22.4-next.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.35-next.0 - - @backstage/backend-defaults@0.2.17-next.0 - - @backstage/plugin-app-backend@0.3.65-next.0 - - @backstage/backend-plugin-api@0.6.17-next.0 - - @backstage/backend-tasks@0.5.22-next.0 - - @backstage/catalog-model@1.4.5 - - @backstage/plugin-adr-backend@0.4.14-next.0 - - @backstage/plugin-auth-backend@0.22.4-next.0 - - @backstage/plugin-auth-backend-module-github-provider@0.1.14-next.0 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.3-next.0 - - @backstage/plugin-auth-node@0.4.12-next.0 - - @backstage/plugin-azure-devops-backend@0.6.4-next.0 - - @backstage/plugin-badges-backend@0.3.14-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4-next.0 - - @backstage/plugin-devtools-backend@0.3.3-next.0 - - @backstage/plugin-entity-feedback-backend@0.2.14-next.0 - - @backstage/plugin-jenkins-backend@0.4.4-next.0 - - @backstage/plugin-lighthouse-backend@0.4.10-next.0 - - @backstage/plugin-linguist-backend@0.5.15-next.0 - - @backstage/plugin-nomad-backend@0.1.19-next.0 - - @backstage/plugin-notifications-backend@0.1.3-next.0 - - @backstage/plugin-permission-backend@0.5.41-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.14-next.0 - - @backstage/plugin-permission-common@0.7.13 - - @backstage/plugin-permission-node@0.7.28-next.0 - - @backstage/plugin-playlist-backend@0.3.21-next.0 - - @backstage/plugin-proxy-backend@0.4.15-next.0 - - @backstage/plugin-scaffolder-backend-module-github@0.2.7-next.0 - - @backstage/plugin-search-backend@1.5.7-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.22-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.21-next.0 - - @backstage/plugin-search-backend-node@1.2.21-next.0 - - @backstage/plugin-sonarqube-backend@0.2.19-next.0 - - @backstage/plugin-todo-backend@0.3.16-next.0 - -## 0.0.24 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.21.0 - - @backstage/plugin-kubernetes-backend@0.16.3 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.3 - - @backstage/plugin-permission-backend@0.5.40 - - @backstage/plugin-proxy-backend@0.4.14 - - @backstage/plugin-scaffolder-backend@1.22.3 - - @backstage/plugin-jenkins-backend@0.4.3 - - @backstage/plugin-auth-backend@0.22.3 - - @backstage/plugin-auth-node@0.4.11 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.2 - - @backstage/plugin-catalog-backend-module-openapi@0.1.34 - - @backstage/plugin-azure-devops-backend@0.6.3 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.10 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.14 - - @backstage/plugin-lighthouse-backend@0.4.9 - - @backstage/plugin-linguist-backend@0.5.14 - - @backstage/plugin-search-backend-module-catalog@0.1.21 - - @backstage/plugin-search-backend-module-techdocs@0.1.21 - - @backstage/plugin-todo-backend@0.3.15 - - @backstage/backend-defaults@0.2.16 - - @backstage/plugin-app-backend@0.3.64 - - @backstage/plugin-adr-backend@0.4.13 - - @backstage/plugin-badges-backend@0.3.13 - - @backstage/plugin-entity-feedback-backend@0.2.13 - - @backstage/plugin-notifications-backend@0.1.2 - - @backstage/plugin-playlist-backend@0.3.20 - - @backstage/plugin-techdocs-backend@1.10.3 - - @backstage/plugin-auth-backend-module-github-provider@0.1.13 - - @backstage/backend-plugin-api@0.6.16 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.13 - - @backstage/plugin-permission-node@0.7.27 - - @backstage/plugin-signals-backend@0.1.2 - - @backstage/backend-tasks@0.5.21 - - @backstage/plugin-devtools-backend@0.3.2 - - @backstage/plugin-nomad-backend@0.1.18 - - @backstage/plugin-scaffolder-backend-module-github@0.2.6 - - @backstage/plugin-search-backend@1.5.6 - - @backstage/plugin-search-backend-module-explore@0.1.20 - - @backstage/plugin-search-backend-node@1.2.20 - - @backstage/plugin-sonarqube-backend@0.2.18 - - @backstage/catalog-model@1.4.5 - - @backstage/plugin-permission-common@0.7.13 - -## 0.0.23 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.20.0 - - @backstage/plugin-kubernetes-backend@0.16.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.2 - - @backstage/plugin-permission-backend@0.5.39 - - @backstage/plugin-catalog-backend-module-openapi@0.1.33 - - @backstage/plugin-auth-backend@0.22.2 - - @backstage/plugin-azure-devops-backend@0.6.2 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.9 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.13 - - @backstage/plugin-jenkins-backend@0.4.2 - - @backstage/plugin-lighthouse-backend@0.4.8 - - @backstage/plugin-linguist-backend@0.5.13 - - @backstage/plugin-scaffolder-backend@1.22.2 - - @backstage/plugin-search-backend-module-catalog@0.1.20 - - @backstage/plugin-search-backend-module-techdocs@0.1.20 - - @backstage/plugin-todo-backend@0.3.14 - - @backstage/backend-defaults@0.2.15 - - @backstage/plugin-app-backend@0.3.63 - - @backstage/plugin-adr-backend@0.4.12 - - @backstage/plugin-auth-node@0.4.10 - - @backstage/plugin-badges-backend@0.3.12 - - @backstage/plugin-entity-feedback-backend@0.2.12 - - @backstage/plugin-notifications-backend@0.1.1 - - @backstage/plugin-playlist-backend@0.3.19 - - @backstage/plugin-techdocs-backend@1.10.2 - - @backstage/backend-tasks@0.5.20 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.1 - - @backstage/plugin-devtools-backend@0.3.1 - - @backstage/plugin-nomad-backend@0.1.17 - - @backstage/plugin-permission-node@0.7.26 - - @backstage/plugin-proxy-backend@0.4.13 - - @backstage/plugin-scaffolder-backend-module-github@0.2.5 - - @backstage/plugin-search-backend@1.5.5 - - @backstage/plugin-search-backend-module-explore@0.1.19 - - @backstage/plugin-search-backend-node@1.2.19 - - @backstage/plugin-signals-backend@0.1.1 - - @backstage/plugin-sonarqube-backend@0.2.17 - - @backstage/backend-plugin-api@0.6.15 - - @backstage/catalog-model@1.4.5 - - @backstage/plugin-auth-backend-module-github-provider@0.1.12 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.12 - - @backstage/plugin-permission-common@0.7.13 - -## 0.0.22 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.19.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.1 - - @backstage/plugin-permission-backend@0.5.38 - - @backstage/plugin-catalog-backend-module-openapi@0.1.32 - - @backstage/plugin-auth-backend@0.22.1 - - @backstage/plugin-azure-devops-backend@0.6.1 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.8 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.12 - - @backstage/plugin-jenkins-backend@0.4.1 - - @backstage/plugin-kubernetes-backend@0.16.1 - - @backstage/plugin-lighthouse-backend@0.4.7 - - @backstage/plugin-linguist-backend@0.5.12 - - @backstage/plugin-scaffolder-backend@1.22.1 - - @backstage/plugin-search-backend-module-catalog@0.1.19 - - @backstage/plugin-search-backend-module-techdocs@0.1.19 - - @backstage/plugin-todo-backend@0.3.13 - - @backstage/plugin-auth-backend-module-github-provider@0.1.11 - - @backstage/plugin-techdocs-backend@1.10.1 - -## 0.0.21 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-notifications-backend@0.1.0 - - @backstage/plugin-scaffolder-backend@1.22.0 - - @backstage/plugin-linguist-backend@0.5.11 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.7 - - @backstage/plugin-catalog-backend-module-unprocessed@0.4.0 - - @backstage/plugin-catalog-backend@1.18.0 - - @backstage/plugin-devtools-backend@0.3.0 - - @backstage/plugin-jenkins-backend@0.4.0 - - @backstage/plugin-search-backend@1.5.4 - - @backstage/plugin-auth-node@0.4.9 - - @backstage/plugin-lighthouse-backend@0.4.6 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.0 - - @backstage/plugin-azure-devops-backend@0.6.0 - - @backstage/plugin-permission-backend@0.5.37 - - @backstage/plugin-signals-backend@0.1.0 - - @backstage/plugin-nomad-backend@0.1.16 - - @backstage/plugin-entity-feedback-backend@0.2.11 - - @backstage/plugin-playlist-backend@0.3.18 - - @backstage/backend-plugin-api@0.6.14 - - @backstage/plugin-auth-backend@0.22.0 - - @backstage/plugin-techdocs-backend@1.10.0 - - @backstage/plugin-scaffolder-backend-module-github@0.2.4 - - @backstage/plugin-permission-common@0.7.13 - - @backstage/plugin-search-backend-module-techdocs@0.1.18 - - @backstage/plugin-search-backend-module-catalog@0.1.18 - - @backstage/plugin-search-backend-module-explore@0.1.18 - - @backstage/backend-defaults@0.2.14 - - @backstage/plugin-kubernetes-backend@0.16.0 - - @backstage/plugin-adr-backend@0.4.11 - - @backstage/plugin-proxy-backend@0.4.12 - - @backstage/backend-tasks@0.5.19 - - @backstage/plugin-search-backend-node@1.2.18 - - @backstage/plugin-app-backend@0.3.62 - - @backstage/plugin-permission-node@0.7.25 - - @backstage/plugin-todo-backend@0.3.12 - - @backstage/plugin-badges-backend@0.3.11 - - @backstage/plugin-auth-backend-module-github-provider@0.1.11 - - @backstage/plugin-catalog-backend-module-openapi@0.1.31 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.11 - - @backstage/plugin-sonarqube-backend@0.2.16 - - @backstage/catalog-model@1.4.5 - -## 0.0.21-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.22.0-next.2 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.7-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.11-next.2 - - @backstage/plugin-catalog-backend@1.18.0-next.2 - - @backstage/plugin-devtools-backend@0.3.0-next.2 - - @backstage/plugin-jenkins-backend@0.4.0-next.2 - - @backstage/plugin-search-backend@1.5.4-next.2 - - @backstage/plugin-techdocs-backend@1.10.0-next.2 - - @backstage/plugin-notifications-backend@0.1.0-next.2 - - @backstage/plugin-linguist-backend@0.5.11-next.2 - - @backstage/plugin-kubernetes-backend@0.16.0-next.2 - - @backstage/plugin-todo-backend@0.3.12-next.2 - - @backstage/plugin-signals-backend@0.1.0-next.2 - - @backstage/plugin-scaffolder-backend-module-github@0.2.4-next.2 - - @backstage/plugin-catalog-backend-module-openapi@0.1.31-next.2 - - @backstage/plugin-adr-backend@0.4.11-next.2 - - @backstage/plugin-azure-devops-backend@0.6.0-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.18-next.2 - - @backstage/plugin-auth-backend@0.22.0-next.2 - - @backstage/backend-defaults@0.2.14-next.2 - - @backstage/plugin-app-backend@0.3.62-next.2 - - @backstage/plugin-auth-node@0.4.9-next.2 - - @backstage/plugin-badges-backend@0.3.11-next.2 - - @backstage/plugin-entity-feedback-backend@0.2.11-next.2 - - @backstage/plugin-lighthouse-backend@0.4.6-next.2 - - @backstage/plugin-playlist-backend@0.3.18-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.18-next.2 - - @backstage/backend-plugin-api@0.6.14-next.2 - - @backstage/backend-tasks@0.5.19-next.2 - - @backstage/catalog-model@1.4.5-next.0 - - @backstage/plugin-auth-backend-module-github-provider@0.1.11-next.2 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.0-next.2 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11-next.2 - - @backstage/plugin-nomad-backend@0.1.16-next.2 - - @backstage/plugin-permission-backend@0.5.37-next.2 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.11-next.2 - - @backstage/plugin-permission-common@0.7.13-next.1 - - @backstage/plugin-permission-node@0.7.25-next.2 - - @backstage/plugin-proxy-backend@0.4.12-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.18-next.2 - - @backstage/plugin-search-backend-node@1.2.18-next.2 - - @backstage/plugin-sonarqube-backend@0.2.16-next.2 - -## 0.0.21-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-entity-feedback-backend@0.2.11-next.1 - - @backstage/plugin-notifications-backend@0.1.0-next.1 - - @backstage/plugin-scaffolder-backend@1.22.0-next.1 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.0-next.1 - - @backstage/plugin-scaffolder-backend-module-github@0.2.4-next.1 - - @backstage/plugin-app-backend@0.3.62-next.1 - - @backstage/plugin-signals-backend@0.1.0-next.1 - - @backstage/plugin-azure-devops-backend@0.6.0-next.1 - - @backstage/plugin-kubernetes-backend@0.16.0-next.1 - - @backstage/backend-plugin-api@0.6.14-next.1 - - @backstage/backend-tasks@0.5.19-next.1 - - @backstage/plugin-adr-backend@0.4.11-next.1 - - @backstage/plugin-auth-backend@0.22.0-next.1 - - @backstage/plugin-auth-node@0.4.9-next.1 - - @backstage/plugin-badges-backend@0.3.11-next.1 - - @backstage/plugin-catalog-backend@1.18.0-next.1 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.7-next.1 - - @backstage/plugin-catalog-backend-module-openapi@0.1.31-next.1 - - @backstage/plugin-devtools-backend@0.3.0-next.1 - - @backstage/plugin-jenkins-backend@0.4.0-next.1 - - @backstage/plugin-lighthouse-backend@0.4.6-next.1 - - @backstage/plugin-linguist-backend@0.5.11-next.1 - - @backstage/plugin-nomad-backend@0.1.16-next.1 - - @backstage/plugin-permission-backend@0.5.37-next.1 - - @backstage/plugin-permission-common@0.7.13-next.1 - - @backstage/plugin-permission-node@0.7.25-next.1 - - @backstage/plugin-playlist-backend@0.3.18-next.1 - - @backstage/plugin-proxy-backend@0.4.12-next.1 - - @backstage/plugin-search-backend@1.5.4-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.18-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.18-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.18-next.1 - - @backstage/plugin-search-backend-node@1.2.18-next.1 - - @backstage/plugin-sonarqube-backend@0.2.16-next.1 - - @backstage/plugin-techdocs-backend@1.9.7-next.1 - - @backstage/plugin-todo-backend@0.3.12-next.1 - - @backstage/backend-defaults@0.2.14-next.1 - - @backstage/catalog-model@1.4.5-next.0 - - @backstage/plugin-auth-backend-module-github-provider@0.1.11-next.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.11-next.1 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.11-next.1 - -## 0.0.21-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-linguist-backend@0.5.10-next.0 - - @backstage/plugin-auth-node@0.4.8-next.0 - - @backstage/plugin-lighthouse-backend@0.4.5-next.0 - - @backstage/plugin-auth-backend-module-guest-provider@0.1.0-next.0 - - @backstage/plugin-playlist-backend@0.3.17-next.0 - - @backstage/backend-plugin-api@0.6.13-next.0 - - @backstage/plugin-entity-feedback-backend@0.2.10-next.0 - - @backstage/plugin-notifications-backend@0.1.0-next.0 - - @backstage/plugin-catalog-backend@1.18.0-next.0 - - @backstage/plugin-auth-backend@0.22.0-next.0 - - @backstage/plugin-jenkins-backend@0.4.0-next.0 - - @backstage/plugin-azure-devops-backend@0.6.0-next.0 - - @backstage/plugin-scaffolder-backend-module-github@0.2.3-next.0 - - @backstage/plugin-scaffolder-backend@1.22.0-next.0 - - @backstage/plugin-permission-common@0.7.13-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.17-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.17-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.17-next.0 - - @backstage/backend-defaults@0.2.13-next.0 - - @backstage/plugin-kubernetes-backend@0.16.0-next.0 - - @backstage/plugin-adr-backend@0.4.10-next.0 - - @backstage/plugin-proxy-backend@0.4.11-next.0 - - @backstage/backend-tasks@0.5.18-next.0 - - @backstage/plugin-search-backend-node@1.2.17-next.0 - - @backstage/plugin-signals-backend@0.0.4-next.0 - - @backstage/plugin-search-backend@1.5.3-next.0 - - @backstage/plugin-devtools-backend@0.3.0-next.0 - - @backstage/plugin-permission-node@0.7.24-next.0 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.6-next.0 - - @backstage/plugin-badges-backend@0.3.10-next.0 - - @backstage/plugin-permission-backend@0.5.36-next.0 - - @backstage/plugin-app-backend@0.3.61-next.0 - - @backstage/plugin-auth-backend-module-github-provider@0.1.10-next.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.30-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.10-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.10-next.0 - - @backstage/plugin-sonarqube-backend@0.2.15-next.0 - - @backstage/plugin-techdocs-backend@1.9.6-next.0 - - @backstage/plugin-nomad-backend@0.1.15-next.0 - - @backstage/plugin-todo-backend@0.3.11-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.10-next.0 - - @backstage/catalog-model@1.4.5-next.0 - -## 0.0.20 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7 - - @backstage/plugin-scaffolder-backend@1.21.0 - - @backstage/plugin-badges-backend@0.3.7 - - @backstage/plugin-azure-devops-backend@0.5.2 - - @backstage/plugin-auth-node@0.4.4 - - @backstage/plugin-entity-feedback-backend@0.2.7 - - @backstage/plugin-lighthouse-backend@0.4.2 - - @backstage/plugin-devtools-backend@0.2.7 - - @backstage/plugin-linguist-backend@0.5.7 - - @backstage/plugin-adr-backend@0.4.7 - - @backstage/plugin-kubernetes-backend@0.15.0 - - @backstage/plugin-signals-backend@0.0.1 - - @backstage/plugin-notifications-backend@0.0.1 - - @backstage/plugin-catalog-backend-module-openapi@0.1.27 - - @backstage/plugin-search-backend-module-techdocs@0.1.14 - - @backstage/plugin-search-backend-module-catalog@0.1.14 - - @backstage/plugin-search-backend-module-explore@0.1.14 - - @backstage/backend-plugin-api@0.6.10 - - @backstage/backend-defaults@0.2.10 - - @backstage/plugin-sonarqube-backend@0.2.12 - - @backstage/plugin-playlist-backend@0.3.14 - - @backstage/plugin-catalog-backend@1.17.0 - - @backstage/plugin-jenkins-backend@0.3.4 - - @backstage/backend-tasks@0.5.15 - - @backstage/plugin-nomad-backend@0.1.12 - - @backstage/plugin-app-backend@0.3.58 - - @backstage/plugin-search-backend@1.5.0 - - @backstage/plugin-todo-backend@0.3.8 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3 - - @backstage/plugin-techdocs-backend@1.9.3 - - @backstage/plugin-permission-backend@0.5.33 - - @backstage/plugin-permission-node@0.7.21 - - @backstage/plugin-proxy-backend@0.4.8 - - @backstage/plugin-search-backend-node@1.2.14 - - @backstage/plugin-permission-common@0.7.12 - -## 0.0.20-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-badges-backend@0.3.7-next.3 - - @backstage/plugin-kubernetes-backend@0.15.0-next.3 - - @backstage/backend-tasks@0.5.15-next.3 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.3 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.3 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.3 - - @backstage/plugin-notifications-backend@0.0.1-next.1 - - @backstage/plugin-signals-backend@0.0.1-next.3 - - @backstage/plugin-catalog-backend@1.17.0-next.3 - - @backstage/plugin-app-backend@0.3.58-next.3 - - @backstage/backend-defaults@0.2.10-next.3 - - @backstage/plugin-adr-backend@0.4.7-next.3 - - @backstage/plugin-auth-node@0.4.4-next.3 - - @backstage/plugin-azure-devops-backend@0.5.2-next.3 - - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.3 - - @backstage/plugin-devtools-backend@0.2.7-next.3 - - @backstage/plugin-entity-feedback-backend@0.2.7-next.3 - - @backstage/plugin-jenkins-backend@0.3.4-next.3 - - @backstage/plugin-lighthouse-backend@0.4.2-next.3 - - @backstage/plugin-linguist-backend@0.5.7-next.3 - - @backstage/plugin-nomad-backend@0.1.12-next.3 - - @backstage/plugin-permission-backend@0.5.33-next.3 - - @backstage/plugin-permission-node@0.7.21-next.3 - - @backstage/plugin-playlist-backend@0.3.14-next.3 - - @backstage/plugin-proxy-backend@0.4.8-next.3 - - @backstage/plugin-scaffolder-backend@1.21.0-next.3 - - @backstage/plugin-search-backend@1.5.0-next.3 - - @backstage/plugin-search-backend-module-catalog@0.1.14-next.3 - - @backstage/plugin-search-backend-module-explore@0.1.14-next.3 - - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.3 - - @backstage/plugin-search-backend-node@1.2.14-next.3 - - @backstage/plugin-sonarqube-backend@0.2.12-next.3 - - @backstage/plugin-techdocs-backend@1.9.3-next.3 - - @backstage/plugin-todo-backend@0.3.8-next.3 - - @backstage/backend-plugin-api@0.6.10-next.3 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.3 - - @backstage/plugin-permission-common@0.7.12 - -## 0.0.20-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.21.0-next.2 - - @backstage/plugin-signals-backend@0.0.1-next.2 - - @backstage/plugin-kubernetes-backend@0.15.0-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.2 - - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.14-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.14-next.2 - - @backstage/plugin-entity-feedback-backend@0.2.7-next.2 - - @backstage/plugin-azure-devops-backend@0.5.2-next.2 - - @backstage/backend-plugin-api@0.6.10-next.2 - - @backstage/plugin-lighthouse-backend@0.4.2-next.2 - - @backstage/backend-defaults@0.2.10-next.2 - - @backstage/plugin-sonarqube-backend@0.2.12-next.2 - - @backstage/plugin-devtools-backend@0.2.7-next.2 - - @backstage/plugin-linguist-backend@0.5.7-next.2 - - @backstage/plugin-playlist-backend@0.3.14-next.2 - - @backstage/plugin-catalog-backend@1.17.0-next.2 - - @backstage/plugin-jenkins-backend@0.3.4-next.2 - - @backstage/backend-tasks@0.5.15-next.2 - - @backstage/plugin-badges-backend@0.3.7-next.2 - - @backstage/plugin-nomad-backend@0.1.12-next.2 - - @backstage/plugin-adr-backend@0.4.7-next.2 - - @backstage/plugin-app-backend@0.3.58-next.2 - - @backstage/plugin-auth-node@0.4.4-next.2 - - @backstage/plugin-notifications-backend@0.0.1-next.0 - - @backstage/plugin-todo-backend@0.3.8-next.2 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.2 - - @backstage/plugin-permission-backend@0.5.33-next.2 - - @backstage/plugin-permission-node@0.7.21-next.2 - - @backstage/plugin-proxy-backend@0.4.8-next.2 - - @backstage/plugin-search-backend@1.5.0-next.2 - - @backstage/plugin-search-backend-node@1.2.14-next.2 - - @backstage/plugin-techdocs-backend@1.9.3-next.2 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.2 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.2 - - @backstage/plugin-permission-common@0.7.12 - -## 0.0.20-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.21.0-next.1 - - @backstage/plugin-azure-devops-backend@0.5.2-next.1 - - @backstage/plugin-catalog-backend@1.17.0-next.1 - - @backstage/backend-plugin-api@0.6.10-next.1 - - @backstage/backend-defaults@0.2.10-next.1 - - @backstage/backend-tasks@0.5.15-next.1 - - @backstage/plugin-adr-backend@0.4.7-next.1 - - @backstage/plugin-app-backend@0.3.58-next.1 - - @backstage/plugin-auth-node@0.4.4-next.1 - - @backstage/plugin-badges-backend@0.3.7-next.1 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.1 - - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.1 - - @backstage/plugin-devtools-backend@0.2.7-next.1 - - @backstage/plugin-entity-feedback-backend@0.2.7-next.1 - - @backstage/plugin-jenkins-backend@0.3.4-next.1 - - @backstage/plugin-kubernetes-backend@0.14.2-next.1 - - @backstage/plugin-lighthouse-backend@0.4.2-next.1 - - @backstage/plugin-linguist-backend@0.5.7-next.1 - - @backstage/plugin-nomad-backend@0.1.12-next.1 - - @backstage/plugin-permission-backend@0.5.33-next.1 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.1 - - @backstage/plugin-permission-common@0.7.12 - - @backstage/plugin-permission-node@0.7.21-next.1 - - @backstage/plugin-playlist-backend@0.3.14-next.1 - - @backstage/plugin-proxy-backend@0.4.8-next.1 - - @backstage/plugin-search-backend@1.5.0-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.14-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.14-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.1 - - @backstage/plugin-search-backend-node@1.2.14-next.1 - - @backstage/plugin-sonarqube-backend@0.2.12-next.1 - - @backstage/plugin-techdocs-backend@1.9.3-next.1 - - @backstage/plugin-todo-backend@0.3.8-next.1 - -## 0.0.20-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-azure-devops-backend@0.5.2-next.0 - - @backstage/plugin-kubernetes-backend@0.14.2-next.0 - - @backstage/plugin-catalog-backend@1.17.0-next.0 - - @backstage/plugin-search-backend@1.5.0-next.0 - - @backstage/plugin-todo-backend@0.3.8-next.0 - - @backstage/plugin-scaffolder-backend@1.21.0-next.0 - - @backstage/plugin-app-backend@0.3.58-next.0 - - @backstage/backend-defaults@0.2.10-next.0 - - @backstage/backend-tasks@0.5.15-next.0 - - @backstage/plugin-auth-node@0.4.4-next.0 - - @backstage/plugin-badges-backend@0.3.7-next.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.0 - - @backstage/plugin-entity-feedback-backend@0.2.7-next.0 - - @backstage/plugin-linguist-backend@0.5.7-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.0 - - @backstage/plugin-permission-node@0.7.21-next.0 - - @backstage/plugin-playlist-backend@0.3.14-next.0 - - @backstage/plugin-proxy-backend@0.4.8-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.14-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.14-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.0 - - @backstage/plugin-sonarqube-backend@0.2.12-next.0 - - @backstage/plugin-techdocs-backend@1.9.3-next.0 - - @backstage/plugin-adr-backend@0.4.7-next.0 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.0 - - @backstage/plugin-devtools-backend@0.2.7-next.0 - - @backstage/plugin-jenkins-backend@0.3.4-next.0 - - @backstage/plugin-lighthouse-backend@0.4.2-next.0 - - @backstage/plugin-nomad-backend@0.1.12-next.0 - - @backstage/plugin-permission-backend@0.5.33-next.0 - - @backstage/plugin-search-backend-node@1.2.14-next.0 - - @backstage/backend-plugin-api@0.6.10-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.0 - - @backstage/plugin-permission-common@0.7.12 - -## 0.0.19 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-sonarqube-backend@0.2.11 - - @backstage/plugin-scaffolder-backend@1.20.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.26 - - @backstage/plugin-search-backend-module-techdocs@0.1.13 - - @backstage/plugin-search-backend-module-catalog@0.1.13 - - @backstage/plugin-search-backend-module-explore@0.1.13 - - @backstage/backend-plugin-api@0.6.9 - - @backstage/backend-defaults@0.2.9 - - @backstage/plugin-azure-devops-backend@0.5.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2 - - @backstage/plugin-entity-feedback-backend@0.2.6 - - @backstage/plugin-devtools-backend@0.2.6 - - @backstage/plugin-linguist-backend@0.5.6 - - @backstage/plugin-playlist-backend@0.3.13 - - @backstage/plugin-techdocs-backend@1.9.2 - - @backstage/plugin-jenkins-backend@0.3.3 - - @backstage/plugin-badges-backend@0.3.6 - - @backstage/plugin-search-backend@1.4.9 - - @backstage/plugin-nomad-backend@0.1.11 - - @backstage/plugin-todo-backend@0.3.7 - - @backstage/plugin-adr-backend@0.4.6 - - @backstage/plugin-app-backend@0.3.57 - - @backstage/plugin-permission-backend@0.5.32 - - @backstage/plugin-permission-common@0.7.12 - - @backstage/plugin-permission-node@0.7.20 - - @backstage/plugin-catalog-backend@1.16.1 - - @backstage/backend-tasks@0.5.14 - - @backstage/plugin-auth-node@0.4.3 - - @backstage/plugin-kubernetes-backend@0.14.1 - - @backstage/plugin-lighthouse-backend@0.4.1 - - @backstage/plugin-proxy-backend@0.4.7 - - @backstage/plugin-search-backend-node@1.2.13 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 - -## 0.0.19-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-sonarqube-backend@0.2.11-next.2 - - @backstage/backend-plugin-api@0.6.9-next.2 - - @backstage/backend-defaults@0.2.9-next.2 - - @backstage/plugin-adr-backend@0.4.6-next.2 - - @backstage/plugin-app-backend@0.3.57-next.2 - - @backstage/plugin-auth-node@0.4.3-next.2 - - @backstage/plugin-azure-devops-backend@0.5.1-next.2 - - @backstage/plugin-badges-backend@0.3.6-next.2 - - @backstage/plugin-catalog-backend@1.16.1-next.2 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.2 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.2 - - @backstage/plugin-devtools-backend@0.2.6-next.2 - - @backstage/plugin-entity-feedback-backend@0.2.6-next.2 - - @backstage/plugin-jenkins-backend@0.3.3-next.2 - - @backstage/plugin-kubernetes-backend@0.14.1-next.2 - - @backstage/plugin-lighthouse-backend@0.4.1-next.2 - - @backstage/plugin-linguist-backend@0.5.6-next.2 - - @backstage/plugin-nomad-backend@0.1.11-next.2 - - @backstage/plugin-permission-backend@0.5.32-next.2 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.2 - - @backstage/plugin-permission-node@0.7.20-next.2 - - @backstage/plugin-playlist-backend@0.3.13-next.2 - - @backstage/plugin-proxy-backend@0.4.7-next.2 - - @backstage/plugin-scaffolder-backend@1.19.3-next.2 - - @backstage/plugin-search-backend@1.4.9-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.13-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.13-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.2 - - @backstage/plugin-search-backend-node@1.2.13-next.2 - - @backstage/plugin-techdocs-backend@1.9.2-next.2 - - @backstage/plugin-todo-backend@0.3.7-next.2 - - @backstage/backend-tasks@0.5.14-next.2 - - @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.2 - -## 0.0.19-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-app-backend@0.3.57-next.1 - - @backstage/plugin-devtools-backend@0.2.6-next.1 - - @backstage/plugin-proxy-backend@0.4.7-next.1 - - @backstage/backend-defaults@0.2.9-next.1 - - @backstage/plugin-kubernetes-backend@0.14.1-next.1 - - @backstage/backend-tasks@0.5.14-next.1 - - @backstage/plugin-adr-backend@0.4.6-next.1 - - @backstage/plugin-auth-node@0.4.3-next.1 - - @backstage/plugin-azure-devops-backend@0.5.1-next.1 - - @backstage/plugin-badges-backend@0.3.6-next.1 - - @backstage/plugin-catalog-backend@1.16.1-next.1 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.1 - - @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.1 - - @backstage/plugin-entity-feedback-backend@0.2.6-next.1 - - @backstage/plugin-jenkins-backend@0.3.3-next.1 - - @backstage/plugin-lighthouse-backend@0.4.1-next.1 - - @backstage/plugin-linguist-backend@0.5.6-next.1 - - @backstage/plugin-nomad-backend@0.1.11-next.1 - - @backstage/plugin-permission-backend@0.5.32-next.1 - - @backstage/plugin-permission-node@0.7.20-next.1 - - @backstage/plugin-playlist-backend@0.3.13-next.1 - - @backstage/plugin-scaffolder-backend@1.19.3-next.1 - - @backstage/plugin-search-backend@1.4.9-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.13-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.13-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.1 - - @backstage/plugin-search-backend-node@1.2.13-next.1 - - @backstage/plugin-sonarqube-backend@0.2.11-next.1 - - @backstage/plugin-techdocs-backend@1.9.2-next.1 - - @backstage/plugin-todo-backend@0.3.7-next.1 - - @backstage/backend-plugin-api@0.6.9-next.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.1 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.1 - - @backstage/plugin-permission-common@0.7.11 - -## 0.0.19-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.19.3-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.13-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.13-next.0 - - @backstage/plugin-azure-devops-backend@0.5.1-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.0 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.0 - - @backstage/plugin-entity-feedback-backend@0.2.6-next.0 - - @backstage/plugin-devtools-backend@0.2.6-next.0 - - @backstage/plugin-linguist-backend@0.5.6-next.0 - - @backstage/plugin-playlist-backend@0.3.13-next.0 - - @backstage/plugin-techdocs-backend@1.9.2-next.0 - - @backstage/plugin-jenkins-backend@0.3.3-next.0 - - @backstage/plugin-badges-backend@0.3.6-next.0 - - @backstage/plugin-search-backend@1.4.9-next.0 - - @backstage/plugin-nomad-backend@0.1.11-next.0 - - @backstage/plugin-todo-backend@0.3.7-next.0 - - @backstage/plugin-adr-backend@0.4.6-next.0 - - @backstage/plugin-app-backend@0.3.57-next.0 - - @backstage/backend-defaults@0.2.9-next.0 - - @backstage/backend-plugin-api@0.6.9-next.0 - - @backstage/backend-tasks@0.5.14-next.0 - - @backstage/plugin-auth-node@0.4.3-next.0 - - @backstage/plugin-catalog-backend@1.16.1-next.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.0 - - @backstage/plugin-kubernetes-backend@0.14.1-next.0 - - @backstage/plugin-lighthouse-backend@0.4.1-next.0 - - @backstage/plugin-permission-backend@0.5.32-next.0 - - @backstage/plugin-permission-common@0.7.11 - - @backstage/plugin-permission-node@0.7.20-next.0 - - @backstage/plugin-proxy-backend@0.4.7-next.0 - - @backstage/plugin-search-backend-node@1.2.13-next.0 - - @backstage/plugin-sonarqube-backend@0.2.11-next.0 - -## 0.0.18 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1 - - @backstage/plugin-techdocs-backend@1.9.1 - - @backstage/plugin-catalog-backend@1.16.0 - - @backstage/plugin-azure-devops-backend@0.5.0 - - @backstage/plugin-scaffolder-backend@1.19.2 - - @backstage/backend-tasks@0.5.13 - - @backstage/plugin-lighthouse-backend@0.4.0 - - @backstage/plugin-kubernetes-backend@0.14.0 - - @backstage/plugin-auth-node@0.4.2 - - @backstage/plugin-permission-backend@0.5.31 - - @backstage/plugin-permission-common@0.7.11 - - @backstage/plugin-playlist-backend@0.3.12 - - @backstage/plugin-permission-node@0.7.19 - - @backstage/plugin-search-backend@1.4.8 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5 - - @backstage/plugin-search-backend-module-techdocs@0.1.12 - - @backstage/plugin-search-backend-module-catalog@0.1.12 - - @backstage/plugin-search-backend-module-explore@0.1.12 - - @backstage/backend-defaults@0.2.8 - - @backstage/plugin-adr-backend@0.4.5 - - @backstage/plugin-app-backend@0.3.56 - - @backstage/plugin-badges-backend@0.3.5 - - @backstage/plugin-catalog-backend-module-openapi@0.1.25 - - @backstage/plugin-devtools-backend@0.2.5 - - @backstage/plugin-entity-feedback-backend@0.2.5 - - @backstage/plugin-jenkins-backend@0.3.2 - - @backstage/plugin-linguist-backend@0.5.5 - - @backstage/plugin-nomad-backend@0.1.10 - - @backstage/plugin-proxy-backend@0.4.6 - - @backstage/plugin-search-backend-node@1.2.12 - - @backstage/plugin-sonarqube-backend@0.2.10 - - @backstage/plugin-todo-backend@0.3.6 - - @backstage/backend-plugin-api@0.6.8 - -## 0.0.18-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-azure-devops-backend@0.5.0-next.3 - - @backstage/plugin-scaffolder-backend@1.19.2-next.3 - - @backstage/backend-defaults@0.2.8-next.3 - - @backstage/backend-plugin-api@0.6.8-next.3 - - @backstage/backend-tasks@0.5.13-next.3 - - @backstage/plugin-adr-backend@0.4.5-next.3 - - @backstage/plugin-app-backend@0.3.56-next.3 - - @backstage/plugin-auth-node@0.4.2-next.3 - - @backstage/plugin-badges-backend@0.3.5-next.3 - - @backstage/plugin-catalog-backend@1.16.0-next.3 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.3 - - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.3 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.3 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.3 - - @backstage/plugin-devtools-backend@0.2.5-next.3 - - @backstage/plugin-entity-feedback-backend@0.2.5-next.3 - - @backstage/plugin-jenkins-backend@0.3.2-next.3 - - @backstage/plugin-kubernetes-backend@0.14.0-next.3 - - @backstage/plugin-lighthouse-backend@0.4.0-next.3 - - @backstage/plugin-linguist-backend@0.5.5-next.3 - - @backstage/plugin-nomad-backend@0.1.10-next.3 - - @backstage/plugin-permission-backend@0.5.31-next.3 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.3 - - @backstage/plugin-permission-common@0.7.10 - - @backstage/plugin-permission-node@0.7.19-next.3 - - @backstage/plugin-playlist-backend@0.3.12-next.3 - - @backstage/plugin-proxy-backend@0.4.6-next.3 - - @backstage/plugin-search-backend@1.4.8-next.3 - - @backstage/plugin-search-backend-module-catalog@0.1.12-next.3 - - @backstage/plugin-search-backend-module-explore@0.1.12-next.3 - - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.3 - - @backstage/plugin-search-backend-node@1.2.12-next.3 - - @backstage/plugin-sonarqube-backend@0.2.10-next.3 - - @backstage/plugin-techdocs-backend@1.9.1-next.3 - - @backstage/plugin-todo-backend@0.3.6-next.3 - -## 0.0.18-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.16.0-next.2 - - @backstage/plugin-lighthouse-backend@0.4.0-next.2 - - @backstage/plugin-auth-node@0.4.2-next.2 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.2 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.12-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.12-next.2 - - @backstage/backend-defaults@0.2.8-next.2 - - @backstage/backend-plugin-api@0.6.8-next.2 - - @backstage/backend-tasks@0.5.13-next.2 - - @backstage/plugin-adr-backend@0.4.5-next.2 - - @backstage/plugin-app-backend@0.3.56-next.2 - - @backstage/plugin-azure-devops-backend@0.5.0-next.2 - - @backstage/plugin-badges-backend@0.3.5-next.2 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.2 - - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.2 - - @backstage/plugin-devtools-backend@0.2.5-next.2 - - @backstage/plugin-entity-feedback-backend@0.2.5-next.2 - - @backstage/plugin-jenkins-backend@0.3.2-next.2 - - @backstage/plugin-kubernetes-backend@0.14.0-next.2 - - @backstage/plugin-linguist-backend@0.5.5-next.2 - - @backstage/plugin-nomad-backend@0.1.10-next.2 - - @backstage/plugin-permission-backend@0.5.31-next.2 - - @backstage/plugin-permission-common@0.7.10 - - @backstage/plugin-permission-node@0.7.19-next.2 - - @backstage/plugin-playlist-backend@0.3.12-next.2 - - @backstage/plugin-proxy-backend@0.4.6-next.2 - - @backstage/plugin-scaffolder-backend@1.19.2-next.2 - - @backstage/plugin-search-backend@1.4.8-next.2 - - @backstage/plugin-search-backend-node@1.2.12-next.2 - - @backstage/plugin-sonarqube-backend@0.2.10-next.2 - - @backstage/plugin-techdocs-backend@1.9.1-next.2 - - @backstage/plugin-todo-backend@0.3.6-next.2 - -## 0.0.18-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.1 - - @backstage/plugin-catalog-backend@1.15.1-next.1 - - @backstage/plugin-azure-devops-backend@0.5.0-next.1 - - @backstage/plugin-kubernetes-backend@0.14.0-next.1 - - @backstage/backend-defaults@0.2.8-next.1 - - @backstage/backend-plugin-api@0.6.8-next.1 - - @backstage/backend-tasks@0.5.13-next.1 - - @backstage/plugin-adr-backend@0.4.5-next.1 - - @backstage/plugin-app-backend@0.3.56-next.1 - - @backstage/plugin-auth-node@0.4.2-next.1 - - @backstage/plugin-badges-backend@0.3.5-next.1 - - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 - - @backstage/plugin-devtools-backend@0.2.5-next.1 - - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 - - @backstage/plugin-jenkins-backend@0.3.2-next.1 - - @backstage/plugin-lighthouse-backend@0.3.5-next.1 - - @backstage/plugin-linguist-backend@0.5.5-next.1 - - @backstage/plugin-nomad-backend@0.1.10-next.1 - - @backstage/plugin-permission-backend@0.5.31-next.1 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.1 - - @backstage/plugin-permission-common@0.7.10 - - @backstage/plugin-permission-node@0.7.19-next.1 - - @backstage/plugin-playlist-backend@0.3.12-next.1 - - @backstage/plugin-proxy-backend@0.4.6-next.1 - - @backstage/plugin-scaffolder-backend@1.19.2-next.1 - - @backstage/plugin-search-backend@1.4.8-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 - - @backstage/plugin-search-backend-node@1.2.12-next.1 - - @backstage/plugin-sonarqube-backend@0.2.10-next.1 - - @backstage/plugin-techdocs-backend@1.9.1-next.1 - - @backstage/plugin-todo-backend@0.3.6-next.1 - -## 0.0.18-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-tasks@0.5.13-next.0 - - @backstage/plugin-scaffolder-backend@1.19.2-next.0 - - @backstage/plugin-kubernetes-backend@0.14.0-next.0 - - @backstage/backend-defaults@0.2.8-next.0 - - @backstage/plugin-adr-backend@0.4.5-next.0 - - @backstage/plugin-app-backend@0.3.56-next.0 - - @backstage/plugin-auth-node@0.4.2-next.0 - - @backstage/plugin-azure-devops-backend@0.4.5-next.0 - - @backstage/plugin-badges-backend@0.3.5-next.0 - - @backstage/plugin-catalog-backend@1.15.1-next.0 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.0 - - @backstage/plugin-devtools-backend@0.2.5-next.0 - - @backstage/plugin-entity-feedback-backend@0.2.5-next.0 - - @backstage/plugin-jenkins-backend@0.3.2-next.0 - - @backstage/plugin-lighthouse-backend@0.3.5-next.0 - - @backstage/plugin-linguist-backend@0.5.5-next.0 - - @backstage/plugin-nomad-backend@0.1.10-next.0 - - @backstage/plugin-permission-backend@0.5.31-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.0 - - @backstage/plugin-permission-node@0.7.19-next.0 - - @backstage/plugin-playlist-backend@0.3.12-next.0 - - @backstage/plugin-proxy-backend@0.4.6-next.0 - - @backstage/plugin-search-backend@1.4.8-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.12-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.12-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.0 - - @backstage/plugin-search-backend-node@1.2.12-next.0 - - @backstage/plugin-sonarqube-backend@0.2.10-next.0 - - @backstage/plugin-techdocs-backend@1.9.1-next.0 - - @backstage/plugin-todo-backend@0.3.6-next.0 - - @backstage/backend-plugin-api@0.6.8-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.0 - - @backstage/plugin-permission-common@0.7.10 - -## 0.0.17 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.15.0 - - @backstage/plugin-kubernetes-backend@0.13.1 - - @backstage/plugin-search-backend-node@1.2.11 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0 - - @backstage/plugin-techdocs-backend@1.9.0 - - @backstage/plugin-scaffolder-backend@1.19.0 - - @backstage/plugin-search-backend@1.4.7 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4 - - @backstage/plugin-entity-feedback-backend@0.2.4 - - @backstage/backend-plugin-api@0.6.7 - - @backstage/plugin-linguist-backend@0.5.4 - - @backstage/plugin-playlist-backend@0.3.11 - - @backstage/backend-tasks@0.5.12 - - @backstage/plugin-badges-backend@0.3.4 - - @backstage/plugin-app-backend@0.3.55 - - @backstage/plugin-search-backend-module-techdocs@0.1.11 - - @backstage/plugin-permission-common@0.7.10 - - @backstage/plugin-jenkins-backend@0.3.1 - - @backstage/plugin-adr-backend@0.4.4 - - @backstage/plugin-proxy-backend@0.4.5 - - @backstage/plugin-catalog-backend-module-openapi@0.1.24 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4 - - @backstage/plugin-lighthouse-backend@0.3.4 - - @backstage/plugin-search-backend-module-catalog@0.1.11 - - @backstage/plugin-todo-backend@0.3.5 - - @backstage/plugin-devtools-backend@0.2.4 - - @backstage/backend-defaults@0.2.7 - - @backstage/plugin-auth-node@0.4.1 - - @backstage/plugin-azure-devops-backend@0.4.4 - - @backstage/plugin-nomad-backend@0.1.9 - - @backstage/plugin-permission-backend@0.5.30 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4 - - @backstage/plugin-permission-node@0.7.18 - - @backstage/plugin-search-backend-module-explore@0.1.11 - - @backstage/plugin-sonarqube-backend@0.2.9 - -## 0.0.17-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.13.1-next.2 - - @backstage/plugin-scaffolder-backend@1.19.0-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.2 - - @backstage/plugin-entity-feedback-backend@0.2.4-next.2 - - @backstage/backend-plugin-api@0.6.7-next.2 - - @backstage/plugin-linguist-backend@0.5.4-next.2 - - @backstage/plugin-playlist-backend@0.3.11-next.2 - - @backstage/plugin-techdocs-backend@1.9.0-next.2 - - @backstage/plugin-catalog-backend@1.15.0-next.2 - - @backstage/backend-tasks@0.5.12-next.2 - - @backstage/plugin-badges-backend@0.3.4-next.2 - - @backstage/plugin-app-backend@0.3.55-next.2 - - @backstage/backend-defaults@0.2.7-next.2 - - @backstage/plugin-adr-backend@0.4.4-next.2 - - @backstage/plugin-auth-node@0.4.1-next.2 - - @backstage/plugin-azure-devops-backend@0.4.4-next.2 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0-next.2 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.2 - - @backstage/plugin-devtools-backend@0.2.4-next.2 - - @backstage/plugin-jenkins-backend@0.3.1-next.2 - - @backstage/plugin-lighthouse-backend@0.3.4-next.2 - - @backstage/plugin-nomad-backend@0.1.9-next.2 - - @backstage/plugin-permission-backend@0.5.30-next.2 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4-next.2 - - @backstage/plugin-permission-node@0.7.18-next.2 - - @backstage/plugin-proxy-backend@0.4.5-next.2 - - @backstage/plugin-search-backend@1.4.7-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.11-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.11-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.2 - - @backstage/plugin-search-backend-node@1.2.11-next.2 - - @backstage/plugin-sonarqube-backend@0.2.9-next.2 - - @backstage/plugin-todo-backend@0.3.5-next.2 - - @backstage/plugin-catalog-backend-module-openapi@0.1.24-next.2 - -## 0.0.17-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.15.0-next.1 - - @backstage/plugin-techdocs-backend@1.9.0-next.1 - - @backstage/plugin-scaffolder-backend@1.19.0-next.1 - - @backstage/plugin-catalog-backend-module-openapi@0.1.24-next.1 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0-next.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.1 - - @backstage/plugin-jenkins-backend@0.3.1-next.1 - - @backstage/plugin-kubernetes-backend@0.13.1-next.1 - - @backstage/plugin-lighthouse-backend@0.3.4-next.1 - - @backstage/plugin-linguist-backend@0.5.4-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.11-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.1 - - @backstage/plugin-todo-backend@0.3.5-next.1 - - @backstage/plugin-adr-backend@0.4.4-next.1 - - @backstage/backend-defaults@0.2.7-next.1 - - @backstage/backend-tasks@0.5.12-next.1 - - @backstage/plugin-app-backend@0.3.55-next.1 - - @backstage/plugin-auth-node@0.4.1-next.1 - - @backstage/plugin-badges-backend@0.3.4-next.1 - - @backstage/plugin-entity-feedback-backend@0.2.4-next.1 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4-next.1 - - @backstage/plugin-permission-node@0.7.18-next.1 - - @backstage/plugin-playlist-backend@0.3.11-next.1 - - @backstage/plugin-proxy-backend@0.4.5-next.1 - - @backstage/plugin-search-backend@1.4.7-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.11-next.1 - - @backstage/plugin-sonarqube-backend@0.2.9-next.1 - - @backstage/plugin-azure-devops-backend@0.4.4-next.1 - - @backstage/plugin-devtools-backend@0.2.4-next.1 - - @backstage/plugin-nomad-backend@0.1.9-next.1 - - @backstage/plugin-permission-backend@0.5.30-next.1 - - @backstage/plugin-search-backend-node@1.2.11-next.1 - - @backstage/backend-plugin-api@0.6.7-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.1 - - @backstage/plugin-permission-common@0.7.9 - -## 0.0.17-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-search-backend-node@1.2.11-next.0 - - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0-next.0 - - @backstage/plugin-techdocs-backend@1.8.1-next.0 - - @backstage/plugin-scaffolder-backend@1.19.0-next.0 - - @backstage/plugin-catalog-backend@1.15.0-next.0 - - @backstage/plugin-search-backend@1.4.7-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.0 - - @backstage/plugin-proxy-backend@0.4.5-next.0 - - @backstage/plugin-app-backend@0.3.55-next.0 - - @backstage/plugin-devtools-backend@0.2.4-next.0 - - @backstage/backend-defaults@0.2.7-next.0 - - @backstage/backend-plugin-api@0.6.7-next.0 - - @backstage/backend-tasks@0.5.12-next.0 - - @backstage/plugin-adr-backend@0.4.4-next.0 - - @backstage/plugin-auth-node@0.4.1-next.0 - - @backstage/plugin-azure-devops-backend@0.4.4-next.0 - - @backstage/plugin-badges-backend@0.3.4-next.0 - - @backstage/plugin-catalog-backend-module-openapi@0.1.24-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.0 - - @backstage/plugin-entity-feedback-backend@0.2.4-next.0 - - @backstage/plugin-jenkins-backend@0.3.1-next.0 - - @backstage/plugin-kubernetes-backend@0.13.1-next.0 - - @backstage/plugin-lighthouse-backend@0.3.4-next.0 - - @backstage/plugin-linguist-backend@0.5.4-next.0 - - @backstage/plugin-nomad-backend@0.1.9-next.0 - - @backstage/plugin-permission-backend@0.5.30-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4-next.0 - - @backstage/plugin-permission-common@0.7.9 - - @backstage/plugin-permission-node@0.7.18-next.0 - - @backstage/plugin-playlist-backend@0.3.11-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.11-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.11-next.0 - - @backstage/plugin-sonarqube-backend@0.2.9-next.0 - - @backstage/plugin-todo-backend@0.3.5-next.0 - -## 0.0.16 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-nomad-backend@0.1.8 - - @backstage/backend-tasks@0.5.11 - - @backstage/plugin-sonarqube-backend@0.2.8 - - @backstage/plugin-scaffolder-backend@1.18.0 - - @backstage/plugin-playlist-backend@0.3.10 - - @backstage/plugin-techdocs-backend@1.8.0 - - @backstage/plugin-catalog-backend@1.14.0 - - @backstage/plugin-auth-node@0.4.0 - - @backstage/plugin-badges-backend@0.3.3 - - @backstage/plugin-kubernetes-backend@0.13.0 - - @backstage/plugin-jenkins-backend@0.3.0 - - @backstage/plugin-search-backend@1.4.6 - - @backstage/backend-plugin-api@0.6.6 - - @backstage/plugin-lighthouse-backend@0.3.3 - - @backstage/plugin-linguist-backend@0.5.3 - - @backstage/plugin-search-backend-module-catalog@0.1.10 - - @backstage/plugin-search-backend-module-explore@0.1.10 - - @backstage/plugin-search-backend-module-techdocs@0.1.10 - - @backstage/plugin-search-backend-node@1.2.10 - - @backstage/backend-defaults@0.2.6 - - @backstage/plugin-adr-backend@0.4.3 - - @backstage/plugin-app-backend@0.3.54 - - @backstage/plugin-azure-devops-backend@0.4.3 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 - - @backstage/plugin-devtools-backend@0.2.3 - - @backstage/plugin-entity-feedback-backend@0.2.3 - - @backstage/plugin-permission-backend@0.5.29 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.3 - - @backstage/plugin-permission-node@0.7.17 - - @backstage/plugin-proxy-backend@0.4.3 - - @backstage/plugin-todo-backend@0.3.4 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 - - @backstage/plugin-permission-common@0.7.9 - -## 0.0.16-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-nomad-backend@0.1.8-next.2 - - @backstage/plugin-scaffolder-backend@1.18.0-next.2 - - @backstage/plugin-techdocs-backend@1.8.0-next.2 - - @backstage/plugin-auth-node@0.4.0-next.2 - - @backstage/plugin-catalog-backend@1.14.0-next.2 - - @backstage/plugin-kubernetes-backend@0.12.3-next.2 - - @backstage/plugin-jenkins-backend@0.2.9-next.2 - - @backstage/backend-defaults@0.2.6-next.2 - - @backstage/backend-tasks@0.5.11-next.2 - - @backstage/plugin-adr-backend@0.4.3-next.2 - - @backstage/plugin-app-backend@0.3.54-next.2 - - @backstage/plugin-azure-devops-backend@0.4.3-next.2 - - @backstage/plugin-badges-backend@0.3.3-next.2 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3-next.2 - - @backstage/plugin-devtools-backend@0.2.3-next.2 - - @backstage/plugin-entity-feedback-backend@0.2.3-next.2 - - @backstage/plugin-lighthouse-backend@0.3.3-next.2 - - @backstage/plugin-linguist-backend@0.5.3-next.2 - - @backstage/plugin-permission-backend@0.5.29-next.2 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.3-next.2 - - @backstage/plugin-permission-node@0.7.17-next.2 - - @backstage/plugin-playlist-backend@0.3.10-next.2 - - @backstage/plugin-proxy-backend@0.4.3-next.2 - - @backstage/plugin-search-backend@1.4.6-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.10-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.10-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.10-next.2 - - @backstage/plugin-search-backend-node@1.2.10-next.2 - - @backstage/plugin-sonarqube-backend@0.2.8-next.2 - - @backstage/plugin-todo-backend@0.3.4-next.2 - - @backstage/backend-plugin-api@0.6.6-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3-next.2 - - @backstage/plugin-permission-common@0.7.9-next.0 - -## 0.0.16-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-tasks@0.5.10-next.1 - - @backstage/plugin-catalog-backend@1.14.0-next.1 - - @backstage/plugin-scaffolder-backend@1.18.0-next.1 - - @backstage/plugin-badges-backend@0.3.2-next.1 - - @backstage/backend-plugin-api@0.6.5-next.1 - - @backstage/plugin-lighthouse-backend@0.3.2-next.1 - - @backstage/plugin-linguist-backend@0.5.2-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 - - @backstage/plugin-search-backend-node@1.2.9-next.1 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 - - @backstage/plugin-kubernetes-backend@0.12.2-next.1 - - @backstage/plugin-todo-backend@0.3.3-next.1 - - @backstage/backend-defaults@0.2.5-next.1 - - @backstage/plugin-adr-backend@0.4.2-next.1 - - @backstage/plugin-app-backend@0.3.53-next.1 - - @backstage/plugin-auth-node@0.3.2-next.1 - - @backstage/plugin-azure-devops-backend@0.4.2-next.1 - - @backstage/plugin-devtools-backend@0.2.2-next.1 - - @backstage/plugin-entity-feedback-backend@0.2.2-next.1 - - @backstage/plugin-permission-backend@0.5.28-next.1 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.1 - - @backstage/plugin-permission-node@0.7.16-next.1 - - @backstage/plugin-playlist-backend@0.3.9-next.1 - - @backstage/plugin-proxy-backend@0.4.2-next.1 - - @backstage/plugin-search-backend@1.4.5-next.1 - - @backstage/plugin-sonarqube-backend@0.2.7-next.1 - - @backstage/plugin-techdocs-backend@1.7.2-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 - - @backstage/plugin-permission-common@0.7.8 - -## 0.0.16-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-sonarqube-backend@0.2.7-next.0 - - @backstage/plugin-playlist-backend@0.3.9-next.0 - - @backstage/plugin-catalog-backend@1.14.0-next.0 - - @backstage/plugin-auth-node@0.3.2-next.0 - - @backstage/plugin-adr-backend@0.4.2-next.0 - - @backstage/plugin-scaffolder-backend@1.17.3-next.0 - - @backstage/plugin-techdocs-backend@1.7.2-next.0 - - @backstage/plugin-todo-backend@0.3.3-next.0 - - @backstage/backend-defaults@0.2.5-next.0 - - @backstage/backend-plugin-api@0.6.5-next.0 - - @backstage/backend-tasks@0.5.10-next.0 - - @backstage/plugin-app-backend@0.3.53-next.0 - - @backstage/plugin-azure-devops-backend@0.4.2-next.0 - - @backstage/plugin-badges-backend@0.3.2-next.0 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 - - @backstage/plugin-devtools-backend@0.2.2-next.0 - - @backstage/plugin-entity-feedback-backend@0.2.2-next.0 - - @backstage/plugin-kubernetes-backend@0.12.2-next.0 - - @backstage/plugin-lighthouse-backend@0.3.2-next.0 - - @backstage/plugin-linguist-backend@0.5.2-next.0 - - @backstage/plugin-permission-backend@0.5.28-next.0 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.0 - - @backstage/plugin-permission-common@0.7.8 - - @backstage/plugin-permission-node@0.7.16-next.0 - - @backstage/plugin-proxy-backend@0.4.2-next.0 - - @backstage/plugin-search-backend@1.4.5-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 - - @backstage/plugin-search-backend-node@1.2.9-next.0 - -## 0.0.15 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.13.0 - - @backstage/plugin-kubernetes-backend@0.12.0 - - @backstage/plugin-techdocs-backend@1.7.0 - - @backstage/plugin-proxy-backend@0.4.0 - - @backstage/plugin-adr-backend@0.4.0 - - @backstage/plugin-azure-devops-backend@0.4.0 - - @backstage/plugin-badges-backend@0.3.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.0 - - @backstage/plugin-devtools-backend@0.2.0 - - @backstage/plugin-entity-feedback-backend@0.2.0 - - @backstage/plugin-lighthouse-backend@0.3.0 - - @backstage/plugin-linguist-backend@0.5.0 - - @backstage/plugin-todo-backend@0.3.0 - - @backstage/plugin-app-backend@0.3.51 - - @backstage/plugin-permission-backend@0.5.26 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.0 - - @backstage/plugin-scaffolder-backend@1.17.0 - - @backstage/plugin-search-backend@1.4.3 - - @backstage/plugin-search-backend-module-catalog@0.1.7 - - @backstage/plugin-search-backend-module-explore@0.1.7 - - @backstage/plugin-search-backend-module-techdocs@0.1.7 - - @backstage/backend-tasks@0.5.8 - - @backstage/plugin-auth-node@0.3.0 - - @backstage/plugin-permission-common@0.7.8 - - @backstage/plugin-permission-node@0.7.14 - - @backstage/backend-plugin-api@0.6.3 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0 - - @backstage/backend-defaults@0.2.3 - - @backstage/plugin-search-backend-node@1.2.7 - -## 0.0.15-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-techdocs-backend@1.7.0-next.3 - - @backstage/plugin-proxy-backend@0.4.0-next.3 - - @backstage/plugin-adr-backend@0.4.0-next.3 - - @backstage/plugin-azure-devops-backend@0.4.0-next.3 - - @backstage/plugin-badges-backend@0.3.0-next.3 - - @backstage/plugin-catalog-backend-module-unprocessed@0.3.0-next.3 - - @backstage/plugin-devtools-backend@0.2.0-next.3 - - @backstage/plugin-entity-feedback-backend@0.2.0-next.3 - - @backstage/plugin-lighthouse-backend@0.3.0-next.3 - - @backstage/plugin-linguist-backend@0.5.0-next.3 - - @backstage/plugin-todo-backend@0.3.0-next.3 - - @backstage/plugin-app-backend@0.3.51-next.3 - - @backstage/plugin-catalog-backend@1.13.0-next.3 - - @backstage/plugin-kubernetes-backend@0.11.6-next.3 - - @backstage/plugin-permission-backend@0.5.26-next.3 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.0-next.1 - - @backstage/plugin-scaffolder-backend@1.17.0-next.3 - - @backstage/plugin-search-backend@1.4.3-next.3 - - @backstage/plugin-search-backend-module-catalog@0.1.7-next.3 - - @backstage/plugin-search-backend-module-explore@0.1.7-next.3 - - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.3 - - @backstage/plugin-permission-common@0.7.8-next.2 - - @backstage/plugin-permission-node@0.7.14-next.3 - - @backstage/backend-plugin-api@0.6.3-next.3 - - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0-next.0 - - @backstage/backend-defaults@0.2.3-next.3 - - @backstage/backend-tasks@0.5.8-next.3 - - @backstage/plugin-auth-node@0.3.0-next.3 - - @backstage/plugin-search-backend-node@1.2.7-next.3 - -## 0.0.15-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.16.6-next.2 - - @backstage/plugin-permission-backend@0.5.26-next.2 - - @backstage/plugin-catalog-backend@1.13.0-next.2 - - @backstage/plugin-badges-backend@0.2.6-next.2 - - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.0-next.0 - - @backstage/backend-tasks@0.5.8-next.2 - - @backstage/backend-defaults@0.2.3-next.2 - - @backstage/plugin-app-backend@0.3.51-next.2 - - @backstage/plugin-auth-node@0.3.0-next.2 - - @backstage/plugin-entity-feedback-backend@0.1.9-next.2 - - @backstage/plugin-kubernetes-backend@0.11.6-next.2 - - @backstage/plugin-linguist-backend@0.4.3-next.2 - - @backstage/plugin-permission-node@0.7.14-next.2 - - @backstage/plugin-proxy-backend@0.3.3-next.2 - - @backstage/plugin-search-backend@1.4.3-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.7-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.7-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.2 - - @backstage/plugin-techdocs-backend@1.7.0-next.2 - - @backstage/plugin-devtools-backend@0.1.6-next.2 - - @backstage/backend-plugin-api@0.6.3-next.2 - - @backstage/plugin-adr-backend@0.3.9-next.2 - - @backstage/plugin-azure-devops-backend@0.3.30-next.2 - - @backstage/plugin-lighthouse-backend@0.2.7-next.2 - - @backstage/plugin-permission-common@0.7.8-next.1 - - @backstage/plugin-search-backend-node@1.2.7-next.2 - - @backstage/plugin-todo-backend@0.2.3-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.2.3-next.2 - -## 0.0.15-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.11.6-next.1 - - @backstage/plugin-catalog-backend@1.13.0-next.1 - - @backstage/plugin-devtools-backend@0.1.6-next.1 - - @backstage/backend-tasks@0.5.8-next.1 - - @backstage/plugin-techdocs-backend@1.7.0-next.1 - - @backstage/plugin-scaffolder-backend@1.16.6-next.1 - - @backstage/backend-plugin-api@0.6.3-next.1 - - @backstage/plugin-adr-backend@0.3.9-next.1 - - @backstage/plugin-app-backend@0.3.51-next.1 - - @backstage/plugin-auth-node@0.3.0-next.1 - - @backstage/plugin-azure-devops-backend@0.3.30-next.1 - - @backstage/plugin-badges-backend@0.2.6-next.1 - - @backstage/plugin-entity-feedback-backend@0.1.9-next.1 - - @backstage/plugin-lighthouse-backend@0.2.7-next.1 - - @backstage/plugin-linguist-backend@0.4.3-next.1 - - @backstage/plugin-permission-backend@0.5.26-next.1 - - @backstage/plugin-permission-common@0.7.8-next.0 - - @backstage/plugin-permission-node@0.7.14-next.1 - - @backstage/plugin-proxy-backend@0.3.3-next.1 - - @backstage/plugin-search-backend@1.4.3-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.7-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.7-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.1 - - @backstage/plugin-search-backend-node@1.2.7-next.1 - - @backstage/plugin-todo-backend@0.2.3-next.1 - - @backstage/backend-defaults@0.2.3-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.2.3-next.1 - -## 0.0.15-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.12.2-next.0 - - @backstage/plugin-scaffolder-backend@1.16.3-next.0 - - @backstage/plugin-auth-node@0.3.0-next.0 - - @backstage/plugin-linguist-backend@0.4.2-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.8-next.0 - - @backstage/backend-tasks@0.5.7-next.0 - - @backstage/plugin-app-backend@0.3.50-next.0 - - @backstage/backend-defaults@0.2.2-next.0 - - @backstage/backend-plugin-api@0.6.2-next.0 - - @backstage/plugin-adr-backend@0.3.8-next.0 - - @backstage/plugin-azure-devops-backend@0.3.29-next.0 - - @backstage/plugin-badges-backend@0.2.5-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.2.2-next.0 - - @backstage/plugin-devtools-backend@0.1.5-next.0 - - @backstage/plugin-kubernetes-backend@0.11.5-next.0 - - @backstage/plugin-lighthouse-backend@0.2.6-next.0 - - @backstage/plugin-permission-backend@0.5.25-next.0 - - @backstage/plugin-permission-common@0.7.7 - - @backstage/plugin-permission-node@0.7.13-next.0 - - @backstage/plugin-proxy-backend@0.3.2-next.0 - - @backstage/plugin-search-backend@1.4.2-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.6-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.6-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.6-next.0 - - @backstage/plugin-search-backend-node@1.2.6-next.0 - - @backstage/plugin-techdocs-backend@1.6.7-next.0 - - @backstage/plugin-todo-backend@0.2.2-next.0 - -## 0.0.14 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-search-backend-module-techdocs@0.1.4 - - @backstage/plugin-search-backend-module-catalog@0.1.4 - - @backstage/plugin-search-backend-module-explore@0.1.4 - - @backstage/plugin-azure-devops-backend@0.3.27 - - @backstage/plugin-kubernetes-backend@0.11.3 - - @backstage/plugin-lighthouse-backend@0.2.4 - - @backstage/plugin-permission-backend@0.5.23 - - @backstage/plugin-scaffolder-backend@1.16.0 - - @backstage/backend-defaults@0.2.0 - - @backstage/plugin-devtools-backend@0.1.3 - - @backstage/plugin-techdocs-backend@1.6.5 - - @backstage/plugin-catalog-backend@1.12.0 - - @backstage/plugin-badges-backend@0.2.3 - - @backstage/plugin-search-backend@1.4.0 - - @backstage/plugin-proxy-backend@0.3.0 - - @backstage/plugin-todo-backend@0.2.0 - - @backstage/plugin-app-backend@0.3.48 - - @backstage/backend-plugin-api@0.6.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0 - - @backstage/plugin-entity-feedback-backend@0.1.6 - - @backstage/plugin-search-backend-node@1.2.4 - - @backstage/plugin-linguist-backend@0.4.0 - - @backstage/plugin-auth-node@0.2.17 - - @backstage/backend-tasks@0.5.5 - - @backstage/plugin-adr-backend@0.3.6 - - @backstage/plugin-permission-node@0.7.11 - - @backstage/plugin-permission-common@0.7.7 - -## 0.0.14-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-search-backend-module-techdocs@0.1.4-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.4-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.4-next.2 - - @backstage/plugin-scaffolder-backend@1.15.2-next.2 - - @backstage/plugin-catalog-backend@1.12.0-next.2 - - @backstage/backend-plugin-api@0.6.0-next.2 - - @backstage/plugin-proxy-backend@0.3.0-next.2 - - @backstage/backend-tasks@0.5.5-next.2 - - @backstage/plugin-app-backend@0.3.48-next.2 - - @backstage/plugin-linguist-backend@0.4.0-next.2 - - @backstage/plugin-techdocs-backend@1.6.5-next.2 - - @backstage/backend-defaults@0.2.0-next.2 - - @backstage/plugin-adr-backend@0.3.6-next.2 - - @backstage/plugin-azure-devops-backend@0.3.27-next.2 - - @backstage/plugin-badges-backend@0.2.3-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.2 - - @backstage/plugin-devtools-backend@0.1.3-next.2 - - @backstage/plugin-entity-feedback-backend@0.1.6-next.2 - - @backstage/plugin-kubernetes-backend@0.11.3-next.2 - - @backstage/plugin-lighthouse-backend@0.2.4-next.2 - - @backstage/plugin-permission-backend@0.5.23-next.2 - - @backstage/plugin-permission-node@0.7.11-next.2 - - @backstage/plugin-search-backend@1.4.0-next.2 - - @backstage/plugin-search-backend-node@1.2.4-next.2 - - @backstage/plugin-todo-backend@0.2.0-next.2 - - @backstage/plugin-auth-node@0.2.17-next.2 - -## 0.0.14-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-search-backend-module-techdocs@0.1.4-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.4-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.4-next.1 - - @backstage/plugin-azure-devops-backend@0.3.27-next.1 - - @backstage/plugin-kubernetes-backend@0.11.3-next.1 - - @backstage/plugin-lighthouse-backend@0.2.4-next.1 - - @backstage/plugin-permission-backend@0.5.23-next.1 - - @backstage/plugin-scaffolder-backend@1.15.2-next.1 - - @backstage/backend-defaults@0.2.0-next.1 - - @backstage/plugin-devtools-backend@0.1.3-next.1 - - @backstage/plugin-techdocs-backend@1.6.5-next.1 - - @backstage/plugin-catalog-backend@1.12.0-next.1 - - @backstage/plugin-badges-backend@0.2.3-next.1 - - @backstage/plugin-search-backend@1.4.0-next.1 - - @backstage/plugin-todo-backend@0.2.0-next.1 - - @backstage/plugin-app-backend@0.3.48-next.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.1 - - @backstage/plugin-entity-feedback-backend@0.1.6-next.1 - - @backstage/plugin-search-backend-node@1.2.4-next.1 - - @backstage/plugin-linguist-backend@0.3.2-next.1 - - @backstage/plugin-auth-node@0.2.17-next.1 - - @backstage/backend-tasks@0.5.5-next.1 - - @backstage/plugin-adr-backend@0.3.6-next.1 - - @backstage/plugin-permission-node@0.7.11-next.1 - - @backstage/plugin-permission-common@0.7.7 - -## 0.0.14-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-linguist-backend@0.3.2-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.0 - - @backstage/plugin-search-backend-node@1.2.4-next.0 - - @backstage/plugin-todo-backend@0.2.0-next.0 - - @backstage/plugin-catalog-backend@1.12.0-next.0 - - @backstage/plugin-search-backend@1.4.0-next.0 - - @backstage/backend-defaults@0.1.13-next.0 - - @backstage/backend-tasks@0.5.5-next.0 - - @backstage/plugin-adr-backend@0.3.6-next.0 - - @backstage/plugin-app-backend@0.3.48-next.0 - - @backstage/plugin-auth-node@0.2.17-next.0 - - @backstage/plugin-azure-devops-backend@0.3.27-next.0 - - @backstage/plugin-badges-backend@0.2.3-next.0 - - @backstage/plugin-devtools-backend@0.1.3-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.6-next.0 - - @backstage/plugin-kubernetes-backend@0.11.3-next.0 - - @backstage/plugin-lighthouse-backend@0.2.4-next.0 - - @backstage/plugin-permission-backend@0.5.23-next.0 - - @backstage/plugin-permission-common@0.7.7 - - @backstage/plugin-permission-node@0.7.11-next.0 - - @backstage/plugin-scaffolder-backend@1.15.2-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.4-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.4-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.4-next.0 - - @backstage/plugin-techdocs-backend@1.6.5-next.0 - -## 0.0.13 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.11.2 - - @backstage/plugin-badges-backend@0.2.2 - - @backstage/plugin-devtools-backend@0.1.2 - - @backstage/plugin-scaffolder-backend@1.15.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1 - - @backstage/plugin-azure-devops-backend@0.3.26 - - @backstage/plugin-linguist-backend@0.3.1 - - @backstage/plugin-adr-backend@0.3.5 - - @backstage/plugin-lighthouse-backend@0.2.3 - - @backstage/plugin-entity-feedback-backend@0.1.5 - - @backstage/plugin-catalog-backend@1.11.0 - - @backstage/backend-defaults@0.1.12 - - @backstage/backend-tasks@0.5.4 - - @backstage/plugin-app-backend@0.3.47 - - @backstage/plugin-auth-node@0.2.16 - - @backstage/plugin-permission-backend@0.5.22 - - @backstage/plugin-permission-common@0.7.7 - - @backstage/plugin-permission-node@0.7.10 - - @backstage/plugin-search-backend@1.3.3 - - @backstage/plugin-search-backend-module-catalog@0.1.3 - - @backstage/plugin-search-backend-module-explore@0.1.3 - - @backstage/plugin-search-backend-module-techdocs@0.1.3 - - @backstage/plugin-search-backend-node@1.2.3 - - @backstage/plugin-techdocs-backend@1.6.4 - - @backstage/plugin-todo-backend@0.1.44 - -## 0.0.13-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-devtools-backend@0.1.2-next.2 - - @backstage/plugin-scaffolder-backend@1.15.1-next.1 - - @backstage/plugin-kubernetes-backend@0.11.2-next.2 - - @backstage/plugin-adr-backend@0.3.5-next.1 - - @backstage/backend-defaults@0.1.12-next.0 - - @backstage/backend-tasks@0.5.4-next.0 - - @backstage/plugin-app-backend@0.3.47-next.0 - - @backstage/plugin-auth-node@0.2.16-next.0 - - @backstage/plugin-azure-devops-backend@0.3.26-next.1 - - @backstage/plugin-badges-backend@0.2.2-next.1 - - @backstage/plugin-catalog-backend@1.11.0-next.0 - - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.5-next.0 - - @backstage/plugin-linguist-backend@0.3.1-next.1 - - @backstage/plugin-permission-backend@0.5.22-next.0 - - @backstage/plugin-permission-common@0.7.7-next.0 - - @backstage/plugin-permission-node@0.7.10-next.0 - - @backstage/plugin-search-backend@1.3.3-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.3-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.3-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.3-next.0 - - @backstage/plugin-search-backend-node@1.2.3-next.0 - - @backstage/plugin-techdocs-backend@1.6.4-next.0 - - @backstage/plugin-todo-backend@0.1.44-next.0 - -## 0.0.13-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.11.2-next.1 - - @backstage/plugin-badges-backend@0.2.2-next.1 - - @backstage/plugin-azure-devops-backend@0.3.26-next.1 - - @backstage/plugin-devtools-backend@0.1.2-next.1 - - @backstage/plugin-linguist-backend@0.3.1-next.1 - -## 0.0.13-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.5-next.0 - - @backstage/plugin-catalog-backend@1.11.0-next.0 - - @backstage/plugin-kubernetes-backend@0.11.2-next.0 - - @backstage/backend-defaults@0.1.12-next.0 - - @backstage/plugin-app-backend@0.3.47-next.0 - - @backstage/plugin-auth-node@0.2.16-next.0 - - @backstage/plugin-permission-backend@0.5.22-next.0 - - @backstage/plugin-permission-common@0.7.7-next.0 - - @backstage/plugin-permission-node@0.7.10-next.0 - - @backstage/plugin-scaffolder-backend@1.15.1-next.0 - - @backstage/plugin-search-backend@1.3.3-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.3-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.3-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.3-next.0 - - @backstage/plugin-search-backend-node@1.2.3-next.0 - - @backstage/plugin-techdocs-backend@1.6.4-next.0 - - @backstage/plugin-todo-backend@0.1.44-next.0 - -## 0.0.12 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.15.0 - - @backstage/plugin-kubernetes-backend@0.11.1 - - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0 - - @backstage/plugin-catalog-backend@1.10.0 - - @backstage/plugin-search-backend@1.3.2 - - @backstage/plugin-search-backend-module-explore@0.1.2 - - @backstage/backend-defaults@0.1.11 - - @backstage/plugin-app-backend@0.3.46 - - @backstage/plugin-auth-node@0.2.15 - - @backstage/plugin-permission-backend@0.5.21 - - @backstage/plugin-permission-node@0.7.9 - - @backstage/plugin-search-backend-module-catalog@0.1.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.2 - - @backstage/plugin-search-backend-node@1.2.2 - - @backstage/plugin-techdocs-backend@1.6.3 - - @backstage/plugin-todo-backend@0.1.43 - - @backstage/plugin-permission-common@0.7.6 - -## 0.0.12-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.15.0-next.3 - - @backstage/plugin-kubernetes-backend@0.11.1-next.3 - - @backstage/plugin-catalog-backend@1.10.0-next.2 - - @backstage/backend-defaults@0.1.11-next.2 - - @backstage/plugin-app-backend@0.3.46-next.2 - - @backstage/plugin-auth-node@0.2.15-next.2 - - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0-next.1 - - @backstage/plugin-permission-backend@0.5.21-next.2 - - @backstage/plugin-permission-common@0.7.6-next.0 - - @backstage/plugin-permission-node@0.7.9-next.2 - - @backstage/plugin-search-backend@1.3.2-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.2-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.2-next.2 - - @backstage/plugin-search-backend-module-techdocs@0.1.2-next.2 - - @backstage/plugin-search-backend-node@1.2.2-next.2 - - @backstage/plugin-techdocs-backend@1.6.3-next.2 - - @backstage/plugin-todo-backend@0.1.43-next.2 - -## 0.0.12-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.11.1-next.2 - - @backstage/plugin-scaffolder-backend@1.15.0-next.2 - -## 0.0.12-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0-next.0 - - @backstage/plugin-catalog-backend@1.9.2-next.1 - - @backstage/plugin-scaffolder-backend@1.15.0-next.1 - - @backstage/backend-defaults@0.1.11-next.1 - - @backstage/plugin-app-backend@0.3.46-next.1 - - @backstage/plugin-auth-node@0.2.15-next.1 - - @backstage/plugin-kubernetes-backend@0.11.1-next.1 - - @backstage/plugin-permission-backend@0.5.21-next.1 - - @backstage/plugin-permission-node@0.7.9-next.1 - - @backstage/plugin-search-backend@1.3.2-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.2-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.2-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.2-next.1 - - @backstage/plugin-search-backend-node@1.2.2-next.1 - - @backstage/plugin-techdocs-backend@1.6.3-next.1 - - @backstage/plugin-todo-backend@0.1.43-next.1 - - @backstage/plugin-permission-common@0.7.6-next.0 - -## 0.0.12-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.14.1-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.2-next.0 - - @backstage/plugin-catalog-backend@1.9.2-next.0 - - @backstage/plugin-kubernetes-backend@0.11.1-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.2-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.2-next.0 - - @backstage/plugin-techdocs-backend@1.6.3-next.0 - - @backstage/plugin-todo-backend@0.1.43-next.0 - - @backstage/plugin-app-backend@0.3.46-next.0 - - @backstage/backend-defaults@0.1.11-next.0 - - @backstage/plugin-auth-node@0.2.15-next.0 - - @backstage/plugin-permission-backend@0.5.21-next.0 - - @backstage/plugin-permission-common@0.7.5 - - @backstage/plugin-permission-node@0.7.9-next.0 - - @backstage/plugin-search-backend@1.3.2-next.0 - - @backstage/plugin-search-backend-node@1.2.2-next.0 - -## 0.0.11 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.14.0 - - @backstage/plugin-catalog-backend@1.9.1 - - @backstage/plugin-kubernetes-backend@0.11.0 - - @backstage/plugin-todo-backend@0.1.42 - - @backstage/plugin-permission-node@0.7.8 - - @backstage/plugin-search-backend@1.3.1 - - @backstage/backend-defaults@0.1.10 - - @backstage/plugin-app-backend@0.3.45 - - @backstage/plugin-auth-node@0.2.14 - - @backstage/plugin-search-backend-module-catalog@0.1.1 - - @backstage/plugin-search-backend-module-explore@0.1.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.1 - - @backstage/plugin-techdocs-backend@1.6.2 - - @backstage/plugin-permission-backend@0.5.20 - - @backstage/plugin-search-backend-node@1.2.1 - - @backstage/plugin-permission-common@0.7.5 - -## 0.0.11-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.9.1-next.2 - - @backstage/plugin-kubernetes-backend@0.11.0-next.2 - - @backstage/plugin-search-backend@1.3.1-next.2 - - @backstage/plugin-scaffolder-backend@1.13.2-next.2 - -## 0.0.11-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.11.0-next.1 - - @backstage/plugin-catalog-backend@1.9.1-next.1 - - @backstage/plugin-scaffolder-backend@1.13.2-next.1 - - @backstage/backend-defaults@0.1.10-next.1 - - @backstage/plugin-app-backend@0.3.45-next.1 - - @backstage/plugin-auth-node@0.2.14-next.1 - - @backstage/plugin-permission-backend@0.5.20-next.1 - - @backstage/plugin-permission-node@0.7.8-next.1 - - @backstage/plugin-search-backend@1.3.1-next.1 - - @backstage/plugin-search-backend-module-catalog@0.1.1-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.1-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.1-next.1 - - @backstage/plugin-search-backend-node@1.2.1-next.1 - - @backstage/plugin-techdocs-backend@1.6.2-next.1 - - @backstage/plugin-todo-backend@0.1.42-next.1 - -## 0.0.11-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-permission-node@0.7.8-next.0 - - @backstage/plugin-scaffolder-backend@1.13.2-next.0 - - @backstage/plugin-kubernetes-backend@0.11.0-next.0 - - @backstage/backend-defaults@0.1.10-next.0 - - @backstage/plugin-app-backend@0.3.45-next.0 - - @backstage/plugin-auth-node@0.2.14-next.0 - - @backstage/plugin-catalog-backend@1.9.1-next.0 - - @backstage/plugin-search-backend@1.3.1-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.1-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.1-next.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.1-next.0 - - @backstage/plugin-techdocs-backend@1.6.2-next.0 - - @backstage/plugin-permission-backend@0.5.20-next.0 - - @backstage/plugin-search-backend-node@1.2.1-next.0 - - @backstage/plugin-todo-backend@0.1.42-next.0 - - @backstage/plugin-permission-common@0.7.5 - -## 0.0.10 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.10.0 - - @backstage/plugin-scaffolder-backend@1.13.0 - - @backstage/plugin-catalog-backend@1.9.0 - - @backstage/plugin-permission-node@0.7.7 - - @backstage/plugin-permission-backend@0.5.19 - - @backstage/plugin-search-backend@1.3.0 - - @backstage/plugin-permission-common@0.7.5 - - @backstage/plugin-techdocs-backend@1.6.1 - - @backstage/plugin-search-backend-node@1.2.0 - - @backstage/plugin-search-backend-module-techdocs@0.1.0 - - @backstage/plugin-search-backend-module-catalog@0.1.0 - - @backstage/plugin-search-backend-module-explore@0.1.0 - - @backstage/backend-defaults@0.1.9 - - @backstage/plugin-app-backend@0.3.44 - - @backstage/plugin-auth-node@0.2.13 - - @backstage/plugin-todo-backend@0.1.41 - -## 0.0.10-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.10.0-next.3 - - @backstage/plugin-catalog-backend@1.9.0-next.3 - - @backstage/plugin-scaffolder-backend@1.13.0-next.3 - - @backstage/backend-defaults@0.1.9-next.2 - - @backstage/plugin-app-backend@0.3.44-next.2 - - @backstage/plugin-auth-node@0.2.13-next.2 - - @backstage/plugin-permission-backend@0.5.19-next.2 - - @backstage/plugin-permission-common@0.7.5-next.0 - - @backstage/plugin-permission-node@0.7.7-next.2 - - @backstage/plugin-search-backend@1.3.0-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.0-next.2 - - @backstage/plugin-search-backend-module-explore@0.1.0-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.0-next.2 - - @backstage/plugin-search-backend-node@1.2.0-next.2 - - @backstage/plugin-techdocs-backend@1.6.1-next.3 - - @backstage/plugin-todo-backend@0.1.41-next.3 - -## 0.0.10-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.10.0-next.2 - - @backstage/plugin-catalog-backend@1.8.1-next.2 - - @backstage/plugin-permission-node@0.7.7-next.2 - - @backstage/plugin-permission-backend@0.5.19-next.2 - - @backstage/plugin-scaffolder-backend@1.13.0-next.2 - - @backstage/backend-defaults@0.1.9-next.2 - - @backstage/plugin-app-backend@0.3.44-next.2 - - @backstage/plugin-auth-node@0.2.13-next.2 - - @backstage/plugin-permission-common@0.7.5-next.0 - - @backstage/plugin-search-backend@1.3.0-next.2 - - @backstage/plugin-search-backend-module-catalog@0.1.0-next.1 - - @backstage/plugin-search-backend-module-explore@0.1.0-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.0-next.1 - - @backstage/plugin-search-backend-node@1.2.0-next.2 - - @backstage/plugin-techdocs-backend@1.6.1-next.2 - - @backstage/plugin-todo-backend@0.1.41-next.2 - -## 0.0.10-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-search-backend@1.3.0-next.1 - - @backstage/plugin-scaffolder-backend@1.13.0-next.1 - - @backstage/plugin-catalog-backend@1.8.1-next.1 - - @backstage/plugin-kubernetes-backend@0.10.0-next.1 - - @backstage/plugin-techdocs-backend@1.6.1-next.1 - - @backstage/plugin-search-backend-node@1.2.0-next.1 - - @backstage/plugin-search-backend-module-techdocs@0.1.0-next.0 - - @backstage/plugin-search-backend-module-catalog@0.1.0-next.0 - - @backstage/plugin-search-backend-module-explore@0.1.0-next.0 - - @backstage/backend-defaults@0.1.9-next.1 - - @backstage/plugin-app-backend@0.3.44-next.1 - - @backstage/plugin-todo-backend@0.1.41-next.1 - -## 0.0.10-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.12.1-next.0 - - @backstage/plugin-catalog-backend@1.8.1-next.0 - - @backstage/backend-defaults@0.1.9-next.0 - - @backstage/plugin-app-backend@0.3.44-next.0 - - @backstage/plugin-techdocs-backend@1.6.1-next.0 - - @backstage/plugin-todo-backend@0.1.41-next.0 - -## 0.0.9 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.12.0 - - @backstage/plugin-catalog-backend@1.8.0 - - @backstage/plugin-todo-backend@0.1.40 - - @backstage/plugin-techdocs-backend@1.6.0 - - @backstage/backend-defaults@0.1.8 - - @backstage/plugin-app-backend@0.3.43 - -## 0.0.9-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.12.0-next.2 - - @backstage/backend-defaults@0.1.8-next.2 - - @backstage/plugin-app-backend@0.3.43-next.2 - - @backstage/plugin-catalog-backend@1.8.0-next.2 - - @backstage/plugin-todo-backend@0.1.40-next.2 - -## 0.0.9-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.12.0-next.1 - - @backstage/plugin-app-backend@0.3.43-next.1 - - @backstage/plugin-catalog-backend@1.8.0-next.1 - - @backstage/plugin-todo-backend@0.1.40-next.1 - - @backstage/backend-defaults@0.1.8-next.1 - -## 0.0.9-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-todo-backend@0.1.40-next.0 - - @backstage/plugin-scaffolder-backend@1.11.1-next.0 - - @backstage/plugin-catalog-backend@1.8.0-next.0 - - @backstage/backend-defaults@0.1.8-next.0 - - @backstage/plugin-app-backend@0.3.43-next.0 - -## 0.0.8 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.7.2 - - @backstage/plugin-scaffolder-backend@1.11.0 - - @backstage/plugin-app-backend@0.3.42 - - @backstage/backend-defaults@0.1.7 - -## 0.0.8-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.7.2-next.2 - - @backstage/plugin-scaffolder-backend@1.11.0-next.2 - - @backstage/plugin-app-backend@0.3.42-next.2 - - @backstage/backend-defaults@0.1.7-next.2 - -## 0.0.8-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.7.2-next.1 - - @backstage/plugin-scaffolder-backend@1.11.0-next.1 - - @backstage/backend-defaults@0.1.7-next.1 - - @backstage/plugin-app-backend@0.3.42-next.1 - -## 0.0.8-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.11.0-next.0 - - @backstage/backend-defaults@0.1.7-next.0 - - @backstage/plugin-app-backend@0.3.42-next.0 - - @backstage/plugin-catalog-backend@1.7.2-next.0 - -## 0.0.7 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.10.0 - - @backstage/backend-defaults@0.1.5 - - @backstage/plugin-app-backend@0.3.40 - - @backstage/plugin-catalog-backend@1.7.0 - -## 0.0.7-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-defaults@0.1.5-next.1 - - @backstage/plugin-scaffolder-backend@1.10.0-next.2 - - @backstage/plugin-catalog-backend@1.7.0-next.2 - - @backstage/plugin-app-backend@0.3.40-next.1 - -## 0.0.7-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-defaults@0.1.5-next.0 - - @backstage/plugin-scaffolder-backend@1.10.0-next.1 - - @backstage/plugin-app-backend@0.3.40-next.0 - - @backstage/plugin-catalog-backend@1.7.0-next.1 - -## 0.0.7-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.9.1-next.0 - - @backstage/plugin-catalog-backend@1.7.0-next.0 - - @backstage/backend-defaults@0.1.4 - - @backstage/plugin-app-backend@0.3.39 - -## 0.0.6 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.9.0 - - @backstage/plugin-catalog-backend@1.6.0 - - @backstage/plugin-app-backend@0.3.39 - - @backstage/backend-defaults@0.1.4 - -## 0.0.6-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.6.0-next.3 - - @backstage/plugin-scaffolder-backend@1.9.0-next.3 - - @backstage/backend-defaults@0.1.4-next.3 - - @backstage/plugin-app-backend@0.3.39-next.3 - -## 0.0.6-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.6.0-next.2 - - @backstage/plugin-app-backend@0.3.39-next.2 - - @backstage/plugin-scaffolder-backend@1.9.0-next.2 - - @backstage/backend-defaults@0.1.4-next.2 - -## 0.0.6-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.6.0-next.1 - - @backstage/plugin-scaffolder-backend@1.8.1-next.1 - - @backstage/plugin-app-backend@0.3.39-next.1 - - @backstage/backend-defaults@0.1.4-next.1 - -## 0.0.6-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.8.1-next.0 - - @backstage/plugin-catalog-backend@1.6.0-next.0 - - @backstage/plugin-app-backend@0.3.39-next.0 - - @backstage/backend-defaults@0.1.4-next.0 - -## 0.0.5 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.5.1 - - @backstage/plugin-scaffolder-backend@1.8.0 - - @backstage/plugin-app-backend@0.3.38 - - @backstage/backend-defaults@0.1.3 - -## 0.0.5-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.8.0-next.2 - - @backstage/plugin-app-backend@0.3.38-next.1 - - @backstage/plugin-catalog-backend@1.5.1-next.1 - - @backstage/backend-defaults@0.1.3-next.1 - -## 0.0.5-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.8.0-next.1 - -## 0.0.5-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.5.1-next.0 - - @backstage/plugin-scaffolder-backend@1.8.0-next.0 - - @backstage/plugin-app-backend@0.3.38-next.0 - - @backstage/backend-defaults@0.1.3-next.0 - -## 0.0.4 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.5.0 - - @backstage/plugin-scaffolder-backend@1.7.0 - - @backstage/backend-defaults@0.1.2 - - @backstage/plugin-app-backend@0.3.37 - -## 0.0.4-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.5.0-next.2 - - @backstage/plugin-scaffolder-backend@1.7.0-next.2 - - @backstage/plugin-app-backend@0.3.37-next.2 - - @backstage/backend-defaults@0.1.2-next.2 - -## 0.0.4-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.7.0-next.1 - - @backstage/backend-defaults@0.1.2-next.1 - - @backstage/plugin-app-backend@0.3.37-next.1 - - @backstage/plugin-catalog-backend@1.4.1-next.1 - -## 0.0.4-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.7.0-next.0 - - @backstage/backend-defaults@0.1.2-next.0 - - @backstage/plugin-catalog-backend@1.4.1-next.0 - - @backstage/plugin-app-backend@0.3.37-next.0 - -## 0.0.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.6.0 - - @backstage/plugin-catalog-backend@1.4.0 - - @backstage/backend-defaults@0.1.1 - -## 0.0.3-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.4.0-next.1 - - @backstage/plugin-scaffolder-backend@1.6.0-next.1 - -## 0.0.3-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.6.0-next.0 - - @backstage/plugin-catalog-backend@1.3.2-next.0 - - @backstage/backend-defaults@0.1.1-next.0 - -## 0.0.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.5.0 - - @backstage/backend-defaults@0.1.0 - - @backstage/plugin-catalog-backend@1.3.1 - -## 0.0.2-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.5.0-next.0 - - @backstage/backend-app-api@0.1.1-next.0 - - @backstage/plugin-catalog-backend@1.3.1-next.0 - -## 0.0.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.3.0 - - @backstage/plugin-scaffolder-backend@1.4.0 - - @backstage/backend-app-api@0.1.0 - -## 0.0.1-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.3.0-next.3 - - @backstage/plugin-scaffolder-backend@1.4.0-next.3 - - @backstage/backend-app-api@0.1.0-next.0 diff --git a/packages/backend-next/README.md b/packages/backend-next/README.md deleted file mode 100644 index 4634e5673f..0000000000 --- a/packages/backend-next/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# example-backend-next - -This is an example backend for [the new Backstage backend system](https://backstage.io/docs/backend-system/). - -Do not use this in your own projects. diff --git a/packages/backend-next/knip-report.md b/packages/backend-next/knip-report.md deleted file mode 100644 index a26b412ee9..0000000000 --- a/packages/backend-next/knip-report.md +++ /dev/null @@ -1,12 +0,0 @@ -# Knip report - -## Unused dependencies (5) - -| Name | Location | Severity | -| :----------------------------------------------- | :----------- | :------- | -| @backstage/plugin-catalog-backend-module-openapi | package.json | error | -| @backstage/plugin-search-backend-node | package.json | error | -| @backstage/plugin-permission-common | package.json | error | -| @backstage/plugin-permission-node | package.json | error | -| @backstage/backend-tasks | package.json | error | - diff --git a/packages/backend-next/src/index.ts b/packages/backend-next/src/index.ts deleted file mode 100644 index a4acd19cf2..0000000000 --- a/packages/backend-next/src/index.ts +++ /dev/null @@ -1,51 +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 { createBackend } from '@backstage/backend-defaults'; - -const backend = createBackend(); - -backend.add(import('@backstage/plugin-auth-backend')); -backend.add(import('./authModuleGithubProvider')); -backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); - -backend.add(import('@backstage/plugin-app-backend/alpha')); -backend.add(import('@backstage/plugin-catalog-backend-module-unprocessed')); -backend.add( - import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), -); -backend.add(import('@backstage/plugin-catalog-backend/alpha')); -backend.add(import('@backstage/plugin-devtools-backend')); -backend.add(import('@backstage/plugin-kubernetes-backend/alpha')); -backend.add( - import('@backstage/plugin-permission-backend-module-allow-all-policy'), -); -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(import('@backstage/plugin-techdocs-backend/alpha')); -backend.add(import('@backstage/plugin-signals-backend')); -backend.add(import('@backstage/plugin-notifications-backend')); - -backend.start(); diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 2e0d578fdc..54055c80ac 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/backend-openapi-utils +## 0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/errors@1.2.4 + +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.18-next.1 + ## 0.1.11-next.0 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index c95e01bfd7..60bb7728b0 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.11-next.0", + "version": "0.1.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 4dccd8d1bc..0676d76360 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/backend-plugin-api +## 0.6.19-next.1 + +### Patch Changes + +- 9e63318: Added an optional `accessRestrictions` to external access service tokens and service principals in general, such that you can limit their access to certain plugins or permissions. +- 0665b7e: Renamed `BackendPluginConfig`, `BackendModuleConfig`, and `ExtensionPointConfig` respectively to `CreateBackendPluginOptions`, `CreateBackendModuleOptions`, and `CreateExtensionPointOptions` to standardize frontend and backend factories signatures. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.14-next.1 + +## 0.6.19-next.0 + +### Patch Changes + +- 6551b3d: Moved the declaration of the `SchedulerService` here, along with prefixed versions of all of the types it depends on, from `@backstage/backend-tasks` +- 1779188: Start using the `isDatabaseConflictError` helper from the `@backstage/backend-plugin-api` package in order to avoid dependency with the soon to deprecate `@backstage/backend-common` package. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + +## 0.6.18 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- 1fedf0c: Removed explicit `toString()` method from `ServiceRef` type. +- Updated dependencies + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-node@0.4.13 + +## 0.6.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + ## 0.6.18-next.0 ### Patch Changes diff --git a/packages/backend-plugin-api/api-report-testUtils.md b/packages/backend-plugin-api/api-report-testUtils.md new file mode 100644 index 0000000000..8c9bba8398 --- /dev/null +++ b/packages/backend-plugin-api/api-report-testUtils.md @@ -0,0 +1,26 @@ +## API Report File for "@backstage/backend-plugin-api" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +// @public +export function overridePackagePathResolution( + options: OverridePackagePathResolutionOptions, +): PackagePathResolutionOverride; + +// @public (undocumented) +export interface OverridePackagePathResolutionOptions { + packageName: string; + path?: string; + paths?: { + [path in string]: string | (() => string); + }; +} + +// @public (undocumented) +export interface PackagePathResolutionOverride { + restore(): void; +} + +// (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 b04c7bc20b..5e59378760 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -8,13 +8,16 @@ import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common'; import { AuthorizePermissionResponse } from '@backstage/plugin-permission-common'; import { Config } from '@backstage/config'; +import { Duration } from 'luxon'; import { Handler } from 'express'; +import { HumanDuration } from '@backstage/types'; import { IdentityApi } from '@backstage/plugin-auth-node'; +import { isChildPath } from '@backstage/cli-common'; import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; import { Knex } from 'knex'; +import { PermissionAttributes } from '@backstage/plugin-permission-common'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; -import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { QueryPermissionRequest } from '@backstage/plugin-permission-common'; import { QueryPermissionResponse } from '@backstage/plugin-permission-common'; import { Readable } from 'stream'; @@ -67,13 +70,8 @@ export interface BackendFeature { $$type: '@backstage/BackendFeature'; } -// @public -export interface BackendModuleConfig { - moduleId: string; - pluginId: string; - // (undocumented) - register(reg: BackendModuleRegistrationPoints): void; -} +// @public @deprecated (undocumented) +export type BackendModuleConfig = CreateBackendModuleOptions; // @public export interface BackendModuleRegistrationPoints { @@ -95,12 +93,8 @@ export interface BackendModuleRegistrationPoints { }): void; } -// @public -export interface BackendPluginConfig { - pluginId: string; - // (undocumented) - register(reg: BackendPluginRegistrationPoints): void; -} +// @public @deprecated (undocumented) +export type BackendPluginConfig = CreateBackendPluginOptions; // @public export interface BackendPluginRegistrationPoints { @@ -134,6 +128,14 @@ export type BackstageNonePrincipal = { type: 'none'; }; +// @public +export type BackstagePrincipalAccessRestrictions = { + permissionNames?: string[]; + permissionAttributes?: { + action?: Array['action']>; + }; +}; + // @public (undocumented) export type BackstagePrincipalTypes = { user: BackstageUserPrincipal; @@ -146,6 +148,7 @@ export type BackstagePrincipalTypes = { export type BackstageServicePrincipal = { type: 'service'; subject: string; + accessRestrictions?: BackstagePrincipalAccessRestrictions; }; // @public (undocumented) @@ -202,26 +205,48 @@ export namespace coreServices { const rootLifecycle: ServiceRef; const rootLogger: ServiceRef; const scheduler: ServiceRef; - const tokenManager: ServiceRef; + const // @deprecated + tokenManager: ServiceRef; const urlReader: ServiceRef; - const identity: ServiceRef; + const // @deprecated + identity: ServiceRef; } // @public export function createBackendModule( - config: BackendModuleConfig, + options: CreateBackendModuleOptions, ): () => BackendFeature; +// @public +export interface CreateBackendModuleOptions { + moduleId: string; + pluginId: string; + // (undocumented) + register(reg: BackendModuleRegistrationPoints): void; +} + // @public export function createBackendPlugin( - config: BackendPluginConfig, + options: CreateBackendPluginOptions, ): () => BackendFeature; +// @public +export interface CreateBackendPluginOptions { + pluginId: string; + // (undocumented) + register(reg: BackendPluginRegistrationPoints): void; +} + // @public export function createExtensionPoint( - config: ExtensionPointConfig, + options: CreateExtensionPointOptions, ): ExtensionPoint; +// @public +export interface CreateExtensionPointOptions { + id: string; +} + // @public export function createServiceFactory< TService, @@ -306,10 +331,8 @@ export type ExtensionPoint = { $$type: '@backstage/ExtensionPoint'; }; -// @public -export interface ExtensionPointConfig { - id: string; -} +// @public @deprecated (undocumented) +export type ExtensionPointConfig = CreateExtensionPointOptions; // @public (undocumented) export interface HttpAuthService { @@ -351,6 +374,11 @@ export interface HttpRouterServiceAuthPolicy { // @public (undocumented) export interface IdentityService extends IdentityApi {} +export { isChildPath }; + +// @public +export function isDatabaseConflictError(e: unknown): boolean; + // @public (undocumented) export interface LifecycleService { addShutdownHook( @@ -447,6 +475,11 @@ export interface PluginServiceFactoryConfig< service: ServiceRef; } +// @public +export function readSchedulerServiceTaskScheduleDefinitionFromConfig( + config: Config, +): SchedulerServiceTaskScheduleDefinition; + // @public export type ReadTreeOptions = { filter?( @@ -496,6 +529,12 @@ export type ReadUrlResponse = { lastModifiedAt?: Date; }; +// @public +export function resolvePackagePath(name: string, ...paths: string[]): string; + +// @public +export function resolveSafeChildPath(base: string, path: string): string; + // @public (undocumented) export interface RootConfigService extends Config {} @@ -527,8 +566,70 @@ export interface RootServiceFactoryConfig< service: ServiceRef; } -// @public (undocumented) -export interface SchedulerService extends PluginTaskScheduler {} +// @public +export interface SchedulerService { + createScheduledTaskRunner( + schedule: SchedulerServiceTaskScheduleDefinition, + ): SchedulerServiceTaskRunner; + getScheduledTasks(): Promise; + scheduleTask( + task: SchedulerServiceTaskScheduleDefinition & + SchedulerServiceTaskInvocationDefinition, + ): Promise; + triggerTask(id: string): Promise; +} + +// @public +export type SchedulerServiceTaskDescriptor = { + id: string; + scope: 'global' | 'local'; + settings: { + version: number; + } & JsonObject; +}; + +// @public +export type SchedulerServiceTaskFunction = + | ((abortSignal: AbortSignal) => void | Promise) + | (() => void | Promise); + +// @public +export interface SchedulerServiceTaskInvocationDefinition { + fn: SchedulerServiceTaskFunction; + id: string; + signal?: AbortSignal; +} + +// @public +export interface SchedulerServiceTaskRunner { + run(task: SchedulerServiceTaskInvocationDefinition): Promise; +} + +// @public +export interface SchedulerServiceTaskScheduleDefinition { + frequency: + | { + cron: string; + } + | Duration + | HumanDuration; + initialDelay?: Duration | HumanDuration; + scope?: 'global' | 'local'; + timeout: Duration | HumanDuration; +} + +// @public +export interface SchedulerServiceTaskScheduleDefinitionConfig { + frequency: + | { + cron: string; + } + | string + | HumanDuration; + initialDelay?: string | HumanDuration; + scope?: 'global' | 'local'; + timeout: string | HumanDuration; +} // @public export type SearchOptions = { diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index e4bfaf3112..7fbd8d8b2f 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.18-next.0", + "version": "0.6.19-next.1", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" @@ -21,6 +21,7 @@ "exports": { ".": "./src/index.ts", "./alpha": "./src/alpha.ts", + "./testUtils": "./src/testUtils.ts", "./package.json": "./package.json" }, "main": "src/index.ts", @@ -30,6 +31,9 @@ "alpha": [ "src/alpha.ts" ], + "testUtils": [ + "src/testUtils.ts" + ], "package.json": [ "package.json" ] @@ -48,16 +52,20 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-tasks": "workspace:^", + "@backstage/cli-common": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/types": "workspace:^", "@types/express": "^4.17.6", + "@types/luxon": "^3.0.0", "express": "^4.17.1", - "knex": "^3.0.0" + "knex": "^3.0.0", + "luxon": "^3.0.0" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^" } } diff --git a/packages/backend-plugin-api/src/index.ts b/packages/backend-plugin-api/src/index.ts index 8e0b23d20b..c2e2a13a89 100644 --- a/packages/backend-plugin-api/src/index.ts +++ b/packages/backend-plugin-api/src/index.ts @@ -22,4 +22,5 @@ export * from './services'; export type { BackendFeature } from './types'; +export * from './paths'; export * from './wiring'; diff --git a/packages/backend-common/src/paths.test.ts b/packages/backend-plugin-api/src/paths.test.ts similarity index 100% rename from packages/backend-common/src/paths.test.ts rename to packages/backend-plugin-api/src/paths.test.ts diff --git a/packages/backend-common/src/paths.ts b/packages/backend-plugin-api/src/paths.ts similarity index 100% rename from packages/backend-common/src/paths.ts rename to packages/backend-plugin-api/src/paths.ts diff --git a/packages/backend-plugin-api/src/services/definitions/AuthService.ts b/packages/backend-plugin-api/src/services/definitions/AuthService.ts index 827b4122cd..000ce8bbb1 100644 --- a/packages/backend-plugin-api/src/services/definitions/AuthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/AuthService.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { PermissionAttributes } from '@backstage/plugin-permission-common'; import { JsonObject } from '@backstage/types'; /** @@ -40,6 +41,54 @@ export type BackstageServicePrincipal = { // Exact format TBD, possibly 'plugin:' or 'external:' subject: string; + + /** + * The access restrictions that apply to this principal. + * + * @remarks + * + * If no access restrictions are provided the principal is assumed to have + * unlimited access, at a framework level. The permissions system and + * individual plugins may or may not still apply additional access controls on + * top of this. + */ + accessRestrictions?: BackstagePrincipalAccessRestrictions; +}; + +/** + * The access restrictions that apply to a given principal. + * + * @public + */ +export type BackstagePrincipalAccessRestrictions = { + /** + * If given, the principal is limited to only performing actions with these + * named permissions. + * + * 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. + * + * This array always has at least one element, or is missing entirely. + */ + permissionNames?: string[]; + /** + * If given, the principal 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. + * + * This object always has at least one key, or is missing entirely. + */ + permissionAttributes?: { + /** + * Match any of these action values. This array always has at least one + * element, or is missing entirely. + */ + action?: Array['action']>; + }; }; /** diff --git a/packages/backend-plugin-api/src/services/definitions/SchedulerService.test.ts b/packages/backend-plugin-api/src/services/definitions/SchedulerService.test.ts new file mode 100644 index 0000000000..7b20487af4 --- /dev/null +++ b/packages/backend-plugin-api/src/services/definitions/SchedulerService.test.ts @@ -0,0 +1,140 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { HumanDuration } from '@backstage/types'; +import { Duration } from 'luxon'; +import { readSchedulerServiceTaskScheduleDefinitionFromConfig } from './SchedulerService'; + +describe('readSchedulerServiceTaskScheduleDefinitionFromConfig', () => { + it('all valid values', () => { + const config = new ConfigReader({ + frequency: { + cron: '0 30 * * * *', + }, + timeout: 'PT3M', + initialDelay: { + minutes: 20, + }, + scope: 'global', + }); + + const result = readSchedulerServiceTaskScheduleDefinitionFromConfig(config); + + expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *'); + expect(result.timeout).toEqual(Duration.fromISO('PT3M')); + expect((result.initialDelay as HumanDuration).minutes).toEqual(20); + expect(result.scope).toBe('global'); + }); + + it('all valid required values', () => { + const config = new ConfigReader({ + frequency: { + cron: '0 30 * * * *', + }, + timeout: 'PT3M', + }); + + const result = readSchedulerServiceTaskScheduleDefinitionFromConfig(config); + + expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *'); + expect(result.timeout).toEqual(Duration.fromISO('PT3M')); + expect(result.initialDelay).toBeUndefined(); + expect(result.scope).toBeUndefined(); + }); + + it('fail without required frequency', () => { + const config = new ConfigReader({ + timeout: 'PT3M', + }); + + expect(() => + readSchedulerServiceTaskScheduleDefinitionFromConfig(config), + ).toThrow("Missing required config value at 'frequency'"); + }); + + it('fail without required timeout', () => { + const config = new ConfigReader({ + frequency: 'PT30M', + }); + + expect(() => + readSchedulerServiceTaskScheduleDefinitionFromConfig(config), + ).toThrow("Missing required config value at 'timeout'"); + }); + + it('invalid frequency key', () => { + const config = new ConfigReader({ + frequency: { + invalid: 'value', + }, + timeout: 'PT3M', + }); + + expect(() => + readSchedulerServiceTaskScheduleDefinitionFromConfig(config), + ).toThrow( + "Failed to read duration from config at 'frequency', Error: Needs one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'", + ); + }); + + it('invalid frequency value', () => { + const config = new ConfigReader({ + frequency: { + minutes: 'value', + }, + timeout: 'PT3M', + }); + + expect(() => + readSchedulerServiceTaskScheduleDefinitionFromConfig(config), + ).toThrow( + "Failed to read duration from config, Error: Unable to convert config value for key 'frequency.minutes' in 'mock-config' to a number", + ); + }); + + it('frequency value with additional invalid prop', () => { + const config = new ConfigReader({ + frequency: { + minutes: 20, + invalid: 'value', + }, + timeout: 'PT3M', + }); + + expect(() => + readSchedulerServiceTaskScheduleDefinitionFromConfig(config), + ).toThrow( + "Failed to read duration from config at 'frequency', Error: Unknown property 'invalid'; expected one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'", + ); + }); + + it('invalid scope value', () => { + const config = new ConfigReader({ + frequency: { + years: 2, + }, + timeout: 'PT3M', + scope: 'invalid', + }); + + expect(() => + readSchedulerServiceTaskScheduleDefinitionFromConfig(config), + ).toThrow( + 'Only "global" or "local" are allowed for TaskScheduleDefinition.scope, but got: invalid', + ); + }); +}); diff --git a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts index 07c436bd6b..ad0fc1cf3a 100644 --- a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts +++ b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Backstage Authors + * 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. @@ -14,7 +14,391 @@ * limitations under the License. */ -import { PluginTaskScheduler } from '@backstage/backend-tasks'; +import { Config, readDurationFromConfig } from '@backstage/config'; +import { HumanDuration, JsonObject } from '@backstage/types'; +import { Duration } from 'luxon'; -/** @public */ -export interface SchedulerService extends PluginTaskScheduler {} +/** + * A function that can be called as a scheduled task. + * + * It may optionally accept an abort signal argument. When the signal triggers, + * processing should abort and return as quickly as possible. + * + * @public + */ +export type SchedulerServiceTaskFunction = + | ((abortSignal: AbortSignal) => void | Promise) + | (() => void | Promise); + +/** + * A semi-opaque type to describe an actively scheduled task. + * + * @public + */ +export type SchedulerServiceTaskDescriptor = { + /** + * The unique identifier of the task. + */ + id: string; + /** + * The scope of the task. + */ + scope: 'global' | 'local'; + /** + * The settings that control the task flow. This is a semi-opaque structure + * that is mainly there for debugging purposes. Do not make any assumptions + * about the contents of this field. + */ + settings: { version: number } & JsonObject; +}; + +/** + * Options that control the scheduling of a task. + * + * @public + */ +export interface SchedulerServiceTaskScheduleDefinition { + /** + * How often you want the task to run. The system does its best to avoid + * overlapping invocations. + * + * @remarks + * + * This is the best effort value; under some circumstances there can be + * deviations. For example, if the task runtime is longer than the frequency + * and the timeout has not been given or not been exceeded yet, the next + * invocation of this task will be delayed until after the previous one + * finishes. + * + * This is a required field. + */ + frequency: + | { + /** + * A crontab style string. + * + * @remarks + * + * Overview: + * + * ``` + * ┌────────────── second (optional) + * │ ┌──────────── minute + * │ │ ┌────────── hour + * │ │ │ ┌──────── day of month + * │ │ │ │ ┌────── month + * │ │ │ │ │ ┌──── day of week + * │ │ │ │ │ │ + * │ │ │ │ │ │ + * * * * * * * + * ``` + */ + cron: string; + } + | Duration + | HumanDuration; + + /** + * The maximum amount of time that a single task invocation can take, before + * it's considered timed out and gets "released" such that a new invocation + * is permitted to take place (possibly, then, on a different worker). + */ + timeout: Duration | HumanDuration; + + /** + * The amount of time that should pass before the first invocation happens. + * + * @remarks + * + * This can be useful in cold start scenarios to stagger or delay some heavy + * compute jobs. If no value is given for this field then the first invocation + * will happen as soon as possible according to the cadence. + * + * NOTE: This is a per-worker delay. If you have a cluster of workers all + * collaborating on a task that has its `scope` field set to `'global'`, then + * you may still see the task being processed by other long-lived workers, + * while any given single worker is in its initial sleep delay time e.g. after + * a deployment. Therefore, this parameter is not useful for "globally" pausing + * work; its main intended use is for individual machines to get a chance to + * reach some equilibrium at startup before triggering heavy batch workloads. + */ + initialDelay?: Duration | HumanDuration; + + /** + * Sets the scope of concurrency control / locking to apply for invocations of + * this task. + * + * @remarks + * + * When the scope is set to the default value `'global'`, the scheduler will + * attempt to ensure that only one worker machine runs the task at a time, + * according to the given cadence. This means that as the number of worker + * hosts increases, the invocation frequency of this task will not go up. + * Instead, the load is spread randomly across hosts. This setting is useful + * for tasks that access shared resources, for example catalog ingestion tasks + * where you do not want many machines to repeatedly import the same data and + * trample over each other. + * + * When the scope is set to `'local'`, there is no concurrency control across + * hosts. Each host runs the task according to the given cadence similarly to + * `setInterval`, but the runtime ensures that there are no overlapping runs. + * + * @defaultValue 'global' + */ + scope?: 'global' | 'local'; +} + +/** + * Config options for {@link SchedulerServiceTaskScheduleDefinition} + * that control the scheduling of a task. + * + * @public + */ +export interface SchedulerServiceTaskScheduleDefinitionConfig { + /** + * How often you want the task to run. The system does its best to avoid + * overlapping invocations. + * + * @remarks + * + * This is the best effort value; under some circumstances there can be + * deviations. For example, if the task runtime is longer than the frequency + * and the timeout has not been given or not been exceeded yet, the next + * invocation of this task will be delayed until after the previous one + * finishes. + * + * This is a required field. + */ + frequency: + | { + /** + * A crontab style string. + * + * @remarks + * + * Overview: + * + * ``` + * ┌────────────── second (optional) + * │ ┌──────────── minute + * │ │ ┌────────── hour + * │ │ │ ┌──────── day of month + * │ │ │ │ ┌────── month + * │ │ │ │ │ ┌──── day of week + * │ │ │ │ │ │ + * │ │ │ │ │ │ + * * * * * * * + * ``` + */ + cron: string; + } + | string + | HumanDuration; + + /** + * The maximum amount of time that a single task invocation can take, before + * it's considered timed out and gets "released" such that a new invocation + * is permitted to take place (possibly, then, on a different worker). + */ + timeout: string | HumanDuration; + + /** + * The amount of time that should pass before the first invocation happens. + * + * @remarks + * + * This can be useful in cold start scenarios to stagger or delay some heavy + * compute jobs. If no value is given for this field then the first invocation + * will happen as soon as possible according to the cadence. + * + * NOTE: This is a per-worker delay. If you have a cluster of workers all + * collaborating on a task that has its `scope` field set to `'global'`, then + * you may still see the task being processed by other long-lived workers, + * while any given single worker is in its initial sleep delay time e.g. after + * a deployment. Therefore, this parameter is not useful for "globally" pausing + * work; its main intended use is for individual machines to get a chance to + * reach some equilibrium at startup before triggering heavy batch workloads. + */ + initialDelay?: string | HumanDuration; + + /** + * Sets the scope of concurrency control / locking to apply for invocations of + * this task. + * + * @remarks + * + * When the scope is set to the default value `'global'`, the scheduler will + * attempt to ensure that only one worker machine runs the task at a time, + * according to the given cadence. This means that as the number of worker + * hosts increases, the invocation frequency of this task will not go up. + * Instead, the load is spread randomly across hosts. This setting is useful + * for tasks that access shared resources, for example catalog ingestion tasks + * where you do not want many machines to repeatedly import the same data and + * trample over each other. + * + * When the scope is set to `'local'`, there is no concurrency control across + * hosts. Each host runs the task according to the given cadence similarly to + * `setInterval`, but the runtime ensures that there are no overlapping runs. + * + * @defaultValue 'global' + */ + scope?: 'global' | 'local'; +} + +/** + * Options that apply to the invocation of a given task. + * + * @public + */ +export interface SchedulerServiceTaskInvocationDefinition { + /** + * A unique ID (within the scope of the plugin) for the task. + */ + id: string; + + /** + * The actual task function to be invoked regularly. + */ + fn: SchedulerServiceTaskFunction; + + /** + * An abort signal that, when triggered, will stop the recurring execution of + * the task. + */ + signal?: AbortSignal; +} + +/** + * A previously prepared task schedule, ready to be invoked. + * + * @public + */ +export interface SchedulerServiceTaskRunner { + /** + * Takes the schedule and executes an actual task using it. + * + * @param task - The actual runtime properties of the task + */ + run(task: SchedulerServiceTaskInvocationDefinition): Promise; +} + +/** + * Deals with the scheduling of distributed tasks, for a given plugin. + * + * @public + */ +export interface SchedulerService { + /** + * Manually triggers a task by ID. + * + * If the task doesn't exist, a NotFoundError is thrown. If the task is + * currently running, a ConflictError is thrown. + * + * @param id - The task ID + */ + triggerTask(id: string): Promise; + + /** + * Schedules a task function for recurring runs. + * + * @remarks + * + * The `scope` task field controls whether to use coordinated exclusive + * invocation across workers, or to just coordinate within the current worker. + * + * This convenience method performs both the scheduling and invocation in one + * go. + * + * @param task - The task definition + */ + scheduleTask( + task: SchedulerServiceTaskScheduleDefinition & + SchedulerServiceTaskInvocationDefinition, + ): Promise; + + /** + * Creates a scheduled but dormant recurring task, ready to be launched at a + * later time. + * + * @remarks + * + * This method is useful for pre-creating a schedule in outer code to be + * passed into an inner implementation, such that the outer code controls + * scheduling while inner code controls implementation. + * + * @param schedule - The task schedule + */ + createScheduledTaskRunner( + schedule: SchedulerServiceTaskScheduleDefinition, + ): SchedulerServiceTaskRunner; + + /** + * Returns all scheduled tasks registered to this scheduler. + * + * @remarks + * + * This method is useful for triggering tasks manually using the triggerTask + * functionality. Note that the returned tasks contain only tasks that have + * been initialized in this instance of the scheduler. + * + * @returns Scheduled tasks + */ + getScheduledTasks(): Promise; +} + +function readDuration(config: Config, key: string): Duration | HumanDuration { + if (typeof config.get(key) === 'string') { + const value = config.getString(key); + const duration = Duration.fromISO(value); + if (!duration.isValid) { + throw new Error(`Invalid duration: ${value}`); + } + return duration; + } + + return readDurationFromConfig(config, { key }); +} + +function readCronOrDuration( + config: Config, + key: string, +): { cron: string } | Duration | HumanDuration { + const value = config.get(key); + if (typeof value === 'object' && (value as { cron?: string }).cron) { + return value as { cron: string }; + } + + return readDuration(config, key); +} + +/** + * Reads a {@link SchedulerServiceTaskScheduleDefinition} from config. Expects + * the config not to be the root config, but the config for the definition. + * + * @param config - config for a TaskScheduleDefinition. + * @public + */ +export function readSchedulerServiceTaskScheduleDefinitionFromConfig( + config: Config, +): SchedulerServiceTaskScheduleDefinition { + const frequency = readCronOrDuration(config, 'frequency'); + const timeout = readDuration(config, 'timeout'); + + const initialDelay = config.has('initialDelay') + ? readDuration(config, 'initialDelay') + : undefined; + + const scope = config.getOptionalString('scope'); + if (scope && !['global', 'local'].includes(scope)) { + throw new Error( + `Only "global" or "local" are allowed for TaskScheduleDefinition.scope, but got: ${scope}`, + ); + } + + return { + frequency, + timeout, + initialDelay, + scope: scope as 'global' | 'local' | undefined, + }; +} diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts index c760afc7b4..4e02611f80 100644 --- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts +++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts @@ -172,6 +172,7 @@ export namespace coreServices { * The service reference for the plugin scoped {@link TokenManagerService}. * * @public + * @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead */ export const tokenManager = createServiceRef< import('./TokenManagerService').TokenManagerService @@ -190,6 +191,7 @@ export namespace coreServices { * The service reference for the plugin scoped {@link IdentityService}. * * @public + * @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead */ export const identity = createServiceRef< import('./IdentityService').IdentityService diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index 8a5176379f..f22213a285 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -20,6 +20,7 @@ export type { BackstageCredentials, BackstageUserPrincipal, BackstageServicePrincipal, + BackstagePrincipalAccessRestrictions, BackstagePrincipalTypes, BackstageNonePrincipal, } from './AuthService'; @@ -52,7 +53,16 @@ export type { PluginMetadataService } from './PluginMetadataService'; export type { RootHttpRouterService } from './RootHttpRouterService'; export type { RootLifecycleService } from './RootLifecycleService'; export type { RootLoggerService } from './RootLoggerService'; -export type { SchedulerService } from './SchedulerService'; +export { readSchedulerServiceTaskScheduleDefinitionFromConfig } from './SchedulerService'; +export type { + SchedulerService, + SchedulerServiceTaskDescriptor, + SchedulerServiceTaskFunction, + SchedulerServiceTaskInvocationDefinition, + SchedulerServiceTaskRunner, + SchedulerServiceTaskScheduleDefinition, + SchedulerServiceTaskScheduleDefinitionConfig, +} from './SchedulerService'; export type { TokenManagerService } from './TokenManagerService'; export type { ReadTreeOptions, diff --git a/packages/backend-plugin-api/src/services/index.ts b/packages/backend-plugin-api/src/services/index.ts index dd24127b88..01d3da444b 100644 --- a/packages/backend-plugin-api/src/services/index.ts +++ b/packages/backend-plugin-api/src/services/index.ts @@ -16,3 +16,4 @@ export * from './definitions'; export * from './system'; +export * from './utilities'; diff --git a/packages/backend-common/src/database/util.ts b/packages/backend-plugin-api/src/services/utilities/database.ts similarity index 100% rename from packages/backend-common/src/database/util.ts rename to packages/backend-plugin-api/src/services/utilities/database.ts diff --git a/packages/backend-plugin-api/src/services/utilities/index.ts b/packages/backend-plugin-api/src/services/utilities/index.ts new file mode 100644 index 0000000000..0eec4f3e84 --- /dev/null +++ b/packages/backend-plugin-api/src/services/utilities/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { isDatabaseConflictError } from './database'; diff --git a/packages/backend-plugin-api/src/testUtils.ts b/packages/backend-plugin-api/src/testUtils.ts new file mode 100644 index 0000000000..9616ab1701 --- /dev/null +++ b/packages/backend-plugin-api/src/testUtils.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { packagePathMocks } from './paths'; +import { posix as posixPath, resolve as resolvePath } from 'path'; + +/** @public */ +export interface PackagePathResolutionOverride { + /** Restores the normal behavior of resolvePackagePath */ + restore(): void; +} + +/** @public */ +export interface OverridePackagePathResolutionOptions { + /** The name of the package to mock the resolved path of */ + packageName: string; + + /** A replacement for the root package path */ + path?: string; + + /** + * Replacements for package sub-paths, each key must be an exact match of the posix-style path + * that is being resolved within the package. + * + * For example, code calling `resolvePackagePath('x', 'foo', 'bar')` would match only the following + * configuration: `overridePackagePathResolution({ packageName: 'x', paths: { 'foo/bar': baz } })` + */ + paths?: { [path in string]: string | (() => string) }; +} + +/** + * This utility helps you override the paths returned by `resolvePackagePath` for a given package. + * + * @public + */ +export function overridePackagePathResolution( + options: OverridePackagePathResolutionOptions, +): PackagePathResolutionOverride { + const name = options.packageName; + + if (packagePathMocks.has(name)) { + throw new Error( + `Tried to override resolution for '${name}' more than once for package '${name}'`, + ); + } + + packagePathMocks.set(name, paths => { + const joinedPath = posixPath.join(...paths); + const localResolver = options.paths?.[joinedPath]; + if (localResolver) { + return typeof localResolver === 'function' + ? localResolver() + : localResolver; + } + if (options.path) { + return resolvePath(options.path, ...paths); + } + return undefined; + }); + + return { + restore() { + packagePathMocks.delete(name); + }, + }; +} diff --git a/packages/backend-plugin-api/src/wiring/factories.ts b/packages/backend-plugin-api/src/wiring/factories.ts index 9fa0f87bab..d0199e775a 100644 --- a/packages/backend-plugin-api/src/wiring/factories.ts +++ b/packages/backend-plugin-api/src/wiring/factories.ts @@ -30,7 +30,7 @@ import { * @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 ExtensionPointConfig { +export interface CreateExtensionPointOptions { /** * The ID of this extension point. * @@ -46,15 +46,15 @@ export interface ExtensionPointConfig { * @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points} */ export function createExtensionPoint( - config: ExtensionPointConfig, + options: CreateExtensionPointOptions, ): ExtensionPoint { return { - id: config.id, + id: options.id, get T(): T { throw new Error(`tried to read ExtensionPoint.T of ${this}`); }, toString() { - return `extensionPoint{${config.id}}`; + return `extensionPoint{${options.id}}`; }, $$type: '@backstage/ExtensionPoint', }; @@ -67,7 +67,7 @@ export function createExtensionPoint( * @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 BackendPluginConfig { +export interface CreateBackendPluginOptions { /** * The ID of this plugin. * @@ -85,7 +85,7 @@ export interface BackendPluginConfig { * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} */ export function createBackendPlugin( - config: BackendPluginConfig, + options: CreateBackendPluginOptions, ): () => BackendFeature { const factory: BackendFeatureFactory = () => { let registrations: InternalBackendPluginRegistration[]; @@ -102,7 +102,7 @@ export function createBackendPlugin( let init: InternalBackendPluginRegistration['init'] | undefined = undefined; - config.register({ + options.register({ registerExtensionPoint(ext, impl) { if (init) { throw new Error( @@ -124,14 +124,14 @@ export function createBackendPlugin( if (!init) { throw new Error( - `registerInit was not called by register in ${config.pluginId}`, + `registerInit was not called by register in ${options.pluginId}`, ); } registrations = [ { type: 'plugin', - pluginId: config.pluginId, + pluginId: options.pluginId, extensionPoints, init, }, @@ -152,7 +152,7 @@ export function createBackendPlugin( * @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 BackendModuleConfig { +export interface CreateBackendModuleOptions { /** * Should exactly match the `id` of the plugin that the module extends. * @@ -175,7 +175,7 @@ export interface BackendModuleConfig { * @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns} */ export function createBackendModule( - config: BackendModuleConfig, + options: CreateBackendModuleOptions, ): () => BackendFeature { const factory: BackendFeatureFactory = () => { let registrations: InternalBackendModuleRegistration[]; @@ -192,7 +192,7 @@ export function createBackendModule( let init: InternalBackendModuleRegistration['init'] | undefined = undefined; - config.register({ + options.register({ registerExtensionPoint(ext, impl) { if (init) { throw new Error( @@ -214,15 +214,15 @@ export function createBackendModule( if (!init) { throw new Error( - `registerInit was not called by register in ${config.moduleId} module for ${config.pluginId}`, + `registerInit was not called by register in ${options.moduleId} module for ${options.pluginId}`, ); } registrations = [ { type: 'module', - pluginId: config.pluginId, - moduleId: config.moduleId, + pluginId: options.pluginId, + moduleId: options.moduleId, extensionPoints, init, }, diff --git a/packages/backend-plugin-api/src/wiring/index.ts b/packages/backend-plugin-api/src/wiring/index.ts index 49f15c0b55..5197cec050 100644 --- a/packages/backend-plugin-api/src/wiring/index.ts +++ b/packages/backend-plugin-api/src/wiring/index.ts @@ -14,18 +14,44 @@ * limitations under the License. */ -export type { - BackendModuleConfig, - BackendPluginConfig, - ExtensionPointConfig, +import type { + CreateBackendPluginOptions, + CreateBackendModuleOptions, + CreateExtensionPointOptions, } from './factories'; + export { createBackendModule, createBackendPlugin, createExtensionPoint, } from './factories'; + export type { BackendModuleRegistrationPoints, BackendPluginRegistrationPoints, ExtensionPoint, } from './types'; + +export type { + CreateBackendPluginOptions, + CreateBackendModuleOptions, + CreateExtensionPointOptions, +}; + +/** + * @public + * @deprecated Use {@link CreateBackendPluginOptions} instead. + */ +export type BackendPluginConfig = CreateBackendPluginOptions; + +/** + * @public + * @deprecated Use {@link CreateBackendModuleOptions} instead. + */ +export type BackendModuleConfig = CreateBackendModuleOptions; + +/** + * @public + * @deprecated Use {@link CreateExtensionPointOptions} instead. + */ +export type ExtensionPointConfig = CreateExtensionPointOptions; diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 5fa17ac1fd..a8dd81ce25 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/backend-tasks +## 0.5.24-next.1 + +### Patch Changes + +- ed473cd: Updated the `TaskScheduleDefinitionConfig` deprecated comment to point to `SchedulerServiceTaskScheduleDefinitionConfig` +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + +## 0.5.24-next.0 + +### Patch Changes + +- 736bc3c: Marked all exports as deprecated and pointed at `@backstage/backend-plugin-api` and `@backstage/backend-defaults` +- 6a576dc: Deprecate the legacy `TaskScheduler.fromConfig` method and stop using the `getVoidlogger` in tests files to reduce the dependency on the soon-to-deprecate `backstage-common` package. +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.5.23 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + +## 0.5.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + ## 0.5.23-next.0 ### Patch Changes diff --git a/packages/backend-tasks/api-report.md b/packages/backend-tasks/api-report.md index 00ef28c9ce..6e8d6eeb2f 100644 --- a/packages/backend-tasks/api-report.md +++ b/packages/backend-tasks/api-report.md @@ -14,7 +14,7 @@ import { PluginDatabaseManager } from '@backstage/backend-common'; // @public @deprecated export type HumanDuration = HumanDuration_2; -// @public +// @public @deprecated export interface PluginTaskScheduler { createScheduledTaskRunner(schedule: TaskScheduleDefinition): TaskRunner; getScheduledTasks(): Promise; @@ -24,12 +24,12 @@ export interface PluginTaskScheduler { triggerTask(id: string): Promise; } -// @public +// @public @deprecated export function readTaskScheduleDefinitionFromConfig( config: Config, ): TaskScheduleDefinition; -// @public +// @public @deprecated export type TaskDescriptor = { id: string; scope: 'global' | 'local'; @@ -38,24 +38,24 @@ export type TaskDescriptor = { } & JsonObject; }; -// @public +// @public @deprecated export type TaskFunction = | ((abortSignal: AbortSignal) => void | Promise) | (() => void | Promise); -// @public +// @public @deprecated export interface TaskInvocationDefinition { fn: TaskFunction; id: string; signal?: AbortSignal; } -// @public +// @public @deprecated export interface TaskRunner { run(task: TaskInvocationDefinition): Promise; } -// @public +// @public @deprecated export interface TaskScheduleDefinition { frequency: | { @@ -68,7 +68,7 @@ export interface TaskScheduleDefinition { timeout: Duration | HumanDuration_2; } -// @public +// @public @deprecated export interface TaskScheduleDefinitionConfig { frequency: | { @@ -81,7 +81,7 @@ export interface TaskScheduleDefinitionConfig { timeout: string | HumanDuration_2; } -// @public +// @public @deprecated export class TaskScheduler { constructor( databaseManager: LegacyRootDatabaseService, @@ -94,7 +94,7 @@ export class TaskScheduler { databaseManager: PluginDatabaseManager; logger: LoggerService; }): PluginTaskScheduler; - // (undocumented) + // @deprecated (undocumented) static fromConfig( config: Config, options?: { diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 77d4ff60c7..8a4de36426 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.23-next.0", + "version": "0.5.24-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-tasks/src/database/migrateBackendTasks.ts b/packages/backend-tasks/src/database/migrateBackendTasks.ts index 9530668e3e..ae5048fbf7 100644 --- a/packages/backend-tasks/src/database/migrateBackendTasks.ts +++ b/packages/backend-tasks/src/database/migrateBackendTasks.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { resolvePackagePath } from '@backstage/backend-common'; +import { resolvePackagePath } from '@backstage/backend-plugin-api'; import { Knex } from 'knex'; import { DB_MIGRATIONS_TABLE } from './tables'; diff --git a/packages/backend-tasks/src/deprecated.ts b/packages/backend-tasks/src/deprecated.ts index 4d86cb1700..629e5f6d4d 100644 --- a/packages/backend-tasks/src/deprecated.ts +++ b/packages/backend-tasks/src/deprecated.ts @@ -23,3 +23,5 @@ import { HumanDuration as TypesHumanDuration } from '@backstage/types'; * @deprecated Import from `@backstage/types` instead */ export type HumanDuration = TypesHumanDuration; + +export * from './tasks'; diff --git a/packages/backend-tasks/src/index.ts b/packages/backend-tasks/src/index.ts index d35917056c..0aae81b143 100644 --- a/packages/backend-tasks/src/index.ts +++ b/packages/backend-tasks/src/index.ts @@ -20,5 +20,4 @@ * @packageDocumentation */ -export * from './tasks'; export * from './deprecated'; diff --git a/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts b/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts index 4fd4949478..d4d3d16067 100644 --- a/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts +++ b/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; import { LocalTaskWorker } from './LocalTaskWorker'; +import { mockServices } from '@backstage/backend-test-utils'; describe('LocalTaskWorker', () => { - const logger = getVoidLogger(); + const logger = mockServices.logger.mock(); it('runs the happy path (with iso duration) and handles cancellation', async () => { const fn = jest.fn(); diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts index 4b40791cb5..77965632e9 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts @@ -14,8 +14,11 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; +import { + TestDatabaseId, + TestDatabases, + mockServices, +} from '@backstage/backend-test-utils'; import { ConflictError, NotFoundError } from '@backstage/errors'; import { Duration } from 'luxon'; import { migrateBackendTasks } from '../database/migrateBackendTasks'; @@ -51,10 +54,8 @@ describe('PluginTaskManagerImpl', () => { async function init(databaseId: TestDatabaseId) { const knex = await databases.init(databaseId); await migrateBackendTasks(knex); - const manager = new PluginTaskSchedulerImpl( - async () => knex, - getVoidLogger(), - ); + const logger = mockServices.logger.mock(); + const manager = new PluginTaskSchedulerImpl(async () => knex, logger); return { knex, manager }; } diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts index 1f0363625e..93b5d7d189 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { TestDatabases } from '@backstage/backend-test-utils'; +import { TestDatabases, mockServices } from '@backstage/backend-test-utils'; import { Knex } from 'knex'; import { Duration } from 'luxon'; import waitForExpect from 'wait-for-expect'; @@ -36,7 +35,7 @@ const getTask = async (knex: Knex): Promise => { }; describe('PluginTaskSchedulerJanitor', () => { - const logger = getVoidLogger(); + const logger = mockServices.logger.mock(); const databases = TestDatabases.create({ ids: [ /* 'MYSQL_8' not supported yet */ diff --git a/packages/backend-tasks/src/tasks/TaskScheduler.test.ts b/packages/backend-tasks/src/tasks/TaskScheduler.test.ts index d286eaee38..24ce73712f 100644 --- a/packages/backend-tasks/src/tasks/TaskScheduler.test.ts +++ b/packages/backend-tasks/src/tasks/TaskScheduler.test.ts @@ -14,8 +14,12 @@ * limitations under the License. */ -import { DatabaseManager, getVoidLogger } from '@backstage/backend-common'; -import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; +import { DatabaseManager } from '@backstage/backend-common'; +import { + TestDatabaseId, + TestDatabases, + mockServices, +} from '@backstage/backend-test-utils'; import { Duration } from 'luxon'; import waitForExpect from 'wait-for-expect'; import { TaskScheduler } from './TaskScheduler'; @@ -24,7 +28,7 @@ import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; jest.setTimeout(60_000); describe('TaskScheduler', () => { - const logger = getVoidLogger(); + const logger = mockServices.logger.mock(); const databases = TestDatabases.create(); const testScopedSignal = createTestScopedSignal(); diff --git a/packages/backend-tasks/src/tasks/TaskScheduler.ts b/packages/backend-tasks/src/tasks/TaskScheduler.ts index 672c52cc10..6608ba8e84 100644 --- a/packages/backend-tasks/src/tasks/TaskScheduler.ts +++ b/packages/backend-tasks/src/tasks/TaskScheduler.ts @@ -33,8 +33,13 @@ import { LoggerService } from '@backstage/backend-plugin-api'; * Deals with the scheduling of distributed tasks. * * @public + * @deprecated Please migrate to the new backend system, and depend on `coreServices.scheduler` from `@backstage/backend-plugin-api` instead. */ export class TaskScheduler { + /** + * @deprecated + * It is only used by the legacy backend system, and should not be used in the new backend system. + */ static fromConfig( config: Config, options?: { diff --git a/packages/backend-tasks/src/tasks/TaskWorker.test.ts b/packages/backend-tasks/src/tasks/TaskWorker.test.ts index a2ecdaa779..10ebfde5b4 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.test.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.test.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { TestDatabases } from '@backstage/backend-test-utils'; +import { TestDatabases, mockServices } from '@backstage/backend-test-utils'; import { Duration, DateTime } from 'luxon'; import waitForExpect from 'wait-for-expect'; import { migrateBackendTasks } from '../database/migrateBackendTasks'; @@ -27,7 +26,7 @@ import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; jest.setTimeout(60_000); describe('TaskWorker', () => { - const logger = getVoidLogger(); + const logger = mockServices.logger.mock(); const databases = TestDatabases.create(); const testScopedSignal = createTestScopedSignal(); diff --git a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts index 8053936263..5a173f246b 100644 --- a/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts +++ b/packages/backend-tasks/src/tasks/readTaskScheduleDefinitionFromConfig.ts @@ -51,6 +51,7 @@ function readCronOrDuration( * * @param config - config for a TaskScheduleDefinition. * @public + * @deprecated Please import `readSchedulerServiceTaskScheduleDefinitionFromConfig` from `@backstage/backend-plugin-api` instead */ export function readTaskScheduleDefinitionFromConfig( config: Config, diff --git a/packages/backend-tasks/src/tasks/types.ts b/packages/backend-tasks/src/tasks/types.ts index 14339dda0e..e6a31873be 100644 --- a/packages/backend-tasks/src/tasks/types.ts +++ b/packages/backend-tasks/src/tasks/types.ts @@ -26,6 +26,7 @@ import { z } from 'zod'; * processing should abort and return as quickly as possible. * * @public + * @deprecated Please import `SchedulerServiceTaskFunction` from `@backstage/backend-plugin-api` instead */ export type TaskFunction = | ((abortSignal: AbortSignal) => void | Promise) @@ -35,6 +36,7 @@ export type TaskFunction = * A semi-opaque type to describe an actively scheduled task. * * @public + * @deprecated Please import `SchedulerServiceTaskDescriptor` from `@backstage/backend-plugin-api` instead */ export type TaskDescriptor = { /** @@ -57,6 +59,7 @@ export type TaskDescriptor = { * Options that control the scheduling of a task. * * @public + * @deprecated Please import `SchedulerServiceTaskScheduleDefinition` from `@backstage/backend-plugin-api` instead */ export interface TaskScheduleDefinition { /** @@ -154,6 +157,7 @@ export interface TaskScheduleDefinition { * that control the scheduling of a task. * * @public + * @deprecated Please import `SchedulerServiceTaskScheduleDefinitionConfig` from `@backstage/backend-plugin-api` instead */ export interface TaskScheduleDefinitionConfig { /** @@ -250,6 +254,7 @@ export interface TaskScheduleDefinitionConfig { * Options that apply to the invocation of a given task. * * @public + * @deprecated Please import `SchedulerServiceTaskInvocationDefinition` from `@backstage/backend-plugin-api` instead */ export interface TaskInvocationDefinition { /** @@ -273,6 +278,7 @@ export interface TaskInvocationDefinition { * A previously prepared task schedule, ready to be invoked. * * @public + * @deprecated Please import `SchedulerServiceTaskRunner` from `@backstage/backend-plugin-api` instead */ export interface TaskRunner { /** @@ -287,6 +293,7 @@ export interface TaskRunner { * Deals with the scheduling of distributed tasks, for a given plugin. * * @public + * @deprecated Please use `SchedulerService` from `@backstage/backend-plugin-api` instead (most likely via `coreServices.scheduler`) */ export interface PluginTaskScheduler { /** diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 03886c776d..c9a93857f7 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,68 @@ # @backstage/backend-test-utils +## 0.4.0-next.1 + +### Minor Changes + +- 805cbe7: Added `TestCaches` that functions just like `TestDatabases` + +### Patch Changes + +- 9e63318: Made it possible to give access restrictions to `mockCredentials.service` +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-events-node@0.3.5-next.0 + +## 0.3.9-next.0 + +### Patch Changes + +- 6a576dc: Fix the logger service mock to prevent returning `undefined` from the `child` method. +- Updated dependencies + - @backstage/backend-app-api@0.7.6-next.0 + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-events-node@0.3.5-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## 0.3.8 + +### Patch Changes + +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-app-api@0.7.3 + - @backstage/backend-common@0.22.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/plugin-events-node@0.3.4 + - @backstage/plugin-auth-node@0.4.13 + +## 0.3.8-next.2 + +### Patch Changes + +- 7e5a50d: added `eventsServiceFactory` to `defaultServiceFactories` to resolve issue where different instances of the EventsServices could be used +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + - @backstage/plugin-events-node@0.3.4-next.2 + +## 0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.7.2-next.1 + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + ## 0.3.8-next.0 ### Patch Changes diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index ff3f50ef8c..f3d790ebfe 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -11,12 +11,14 @@ import { Backend } from '@backstage/backend-app-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; import { BackstageCredentials } from '@backstage/backend-plugin-api'; import { BackstageNonePrincipal } from '@backstage/backend-plugin-api'; +import { BackstagePrincipalAccessRestrictions } from '@backstage/backend-plugin-api'; import { BackstageServicePrincipal } from '@backstage/backend-plugin-api'; import { BackstageUserInfo } from '@backstage/backend-plugin-api'; import { BackstageUserPrincipal } from '@backstage/backend-plugin-api'; import { CacheService } from '@backstage/backend-plugin-api'; import { DatabaseService } from '@backstage/backend-plugin-api'; import { DiscoveryService } from '@backstage/backend-plugin-api'; +import { EventsService } from '@backstage/plugin-events-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { HttpAuthService } from '@backstage/backend-plugin-api'; @@ -24,6 +26,7 @@ import { HttpRouterFactoryOptions } from '@backstage/backend-app-api'; import { HttpRouterService } from '@backstage/backend-plugin-api'; import { IdentityService } from '@backstage/backend-plugin-api'; import { JsonObject } from '@backstage/types'; +import Keyv from 'keyv'; import { Knex } from 'knex'; import { LifecycleService } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; @@ -67,6 +70,7 @@ export namespace mockCredentials { } export function service( subject?: string, + accessRestrictions?: BackstagePrincipalAccessRestrictions, ): BackstageCredentials; export namespace service { export function header(options?: TokenOptions): string; @@ -183,6 +187,15 @@ export namespace mockServices { partialImpl?: Partial | undefined, ) => ServiceMock; } + // (undocumented) + export namespace events { + const // (undocumented) + factory: () => ServiceFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; + } export function httpAuth(options?: { pluginId?: string; defaultCredentials?: BackstageCredentials; @@ -413,6 +426,28 @@ export interface TestBackendOptions { >; } +// @public +export type TestCacheId = 'MEMORY' | 'REDIS_7' | 'MEMCACHED_1'; + +// @public +export class TestCaches { + static create(options?: { + ids?: TestCacheId[]; + disableDocker?: boolean; + }): TestCaches; + // (undocumented) + eachSupportedId(): [TestCacheId][]; + init(id: TestCacheId): Promise<{ + store: string; + connection: string; + keyv: Keyv; + }>; + // (undocumented) + static setDefaults(options: { ids?: TestCacheId[] }): void; + // (undocumented) + supports(id: TestCacheId): boolean; +} + // @public export type TestDatabaseId = | 'POSTGRES_16' diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 1d43e24adf..7da7355577 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.3.8-next.0", + "version": "0.4.0-next.1", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" @@ -46,23 +46,29 @@ }, "dependencies": { "@backstage/backend-app-api": "workspace:^", - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", "@backstage/types": "workspace:^", + "@keyv/memcache": "^1.3.5", + "@keyv/redis": "^2.5.3", + "@types/keyv": "^4.2.0", "better-sqlite3": "^9.0.0", "cookie": "^0.6.0", "express": "^4.17.1", "fs-extra": "^11.0.0", + "keyv": "^4.5.2", "knex": "^3.0.0", "msw": "^1.0.0", "mysql2": "^3.0.0", "pg": "^8.11.3", + "pg-connection-string": "^2.3.0", "testcontainers": "^10.0.0", "textextensions": "^5.16.0", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "yn": "^4.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/backend-test-utils/src/cache/TestCaches.test.ts b/packages/backend-test-utils/src/cache/TestCaches.test.ts new file mode 100644 index 0000000000..7d5ef69704 --- /dev/null +++ b/packages/backend-test-utils/src/cache/TestCaches.test.ts @@ -0,0 +1,53 @@ +/* + * 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 { isDockerDisabledForTests } from '../util'; +import { TestCaches } from './TestCaches'; + +const itIfDocker = isDockerDisabledForTests() ? it.skip : it; + +jest.setTimeout(60_000); + +describe('TestCaches', () => { + const caches = TestCaches.create(); + + it.each(caches.eachSupportedId())('fires up a cache, %p', async cacheId => { + const { keyv } = await caches.init(cacheId); + await keyv.set('test', 'value'); + await expect(keyv.get('test')).resolves.toBe('value'); + }); + + itIfDocker('clears between tests, part 1', async () => { + const { keyv } = await caches.init('REDIS_7'); + // eslint-disable-next-line jest/no-standalone-expect + await expect(keyv.get('collision')).resolves.toBeUndefined(); + await keyv.set('collision', 'something'); + }); + + itIfDocker('clears between tests, part 2', async () => { + const { keyv } = await caches.init('REDIS_7'); + // eslint-disable-next-line jest/no-standalone-expect + await expect(keyv.get('collision')).resolves.toBeUndefined(); + await keyv.set('collision', 'something'); + }); + + itIfDocker('clears between tests, part 3', async () => { + const { keyv } = await caches.init('REDIS_7'); + // eslint-disable-next-line jest/no-standalone-expect + await expect(keyv.get('collision')).resolves.toBeUndefined(); + await keyv.set('collision', 'something'); + }); +}); diff --git a/packages/backend-test-utils/src/cache/TestCaches.ts b/packages/backend-test-utils/src/cache/TestCaches.ts new file mode 100644 index 0000000000..e9ba0e5c4f --- /dev/null +++ b/packages/backend-test-utils/src/cache/TestCaches.ts @@ -0,0 +1,210 @@ +/* + * 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 Keyv from 'keyv'; +import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; +import { connectToExternalMemcache, startMemcachedContainer } from './memcache'; +import { connectToExternalRedis, startRedisContainer } from './redis'; +import { Instance, TestCacheId, TestCacheProperties, allCaches } from './types'; + +/** + * Encapsulates the creation of ephemeral test cache instances for use inside + * unit or integration tests. + * + * @public + */ +export class TestCaches { + private readonly instanceById: Map; + private readonly supportedIds: TestCacheId[]; + private static defaultIds?: TestCacheId[]; + + /** + * Creates an empty `TestCaches` instance, and sets up Jest to clean up all of + * its acquired resources after all tests finish. + * + * You typically want to create just a single instance like this at the top of + * your test file or `describe` block, and then call `init` many times on that + * instance inside the individual tests. Spinning up a "physical" cache + * instance takes a considerable amount of time, slowing down tests. But + * wiping the contents of an instance using `init` is very fast. + */ + static create(options?: { + ids?: TestCacheId[]; + disableDocker?: boolean; + }): TestCaches { + const ids = options?.ids; + const disableDocker = options?.disableDocker ?? isDockerDisabledForTests(); + + let testCacheIds: TestCacheId[]; + if (ids) { + testCacheIds = ids; + } else if (TestCaches.defaultIds) { + testCacheIds = TestCaches.defaultIds; + } else { + testCacheIds = Object.keys(allCaches) as TestCacheId[]; + } + + const supportedIds = testCacheIds.filter(id => { + const properties = allCaches[id]; + if (!properties) { + return false; + } + // If the caller has set up the env with an explicit connection string, + // we'll assume that this target will work + if ( + properties.connectionStringEnvironmentVariableName && + process.env[properties.connectionStringEnvironmentVariableName] + ) { + return true; + } + // If the cache doesn't require docker at all, there's nothing to worry + // about + if (!properties.dockerImageName) { + return true; + } + // If the cache requires docker, but docker is disabled, we will fail. + if (disableDocker) { + return false; + } + return true; + }); + + const caches = new TestCaches(supportedIds); + + if (supportedIds.length > 0) { + afterAll(async () => { + await caches.shutdown(); + }); + } + + return caches; + } + + static setDefaults(options: { ids?: TestCacheId[] }) { + TestCaches.defaultIds = options.ids; + } + + private constructor(supportedIds: TestCacheId[]) { + this.instanceById = new Map(); + this.supportedIds = supportedIds; + } + + supports(id: TestCacheId): boolean { + return this.supportedIds.includes(id); + } + + eachSupportedId(): [TestCacheId][] { + return this.supportedIds.map(id => [id]); + } + + /** + * Returns a fresh, empty cache for the given driver. + * + * @param id - The ID of the cache to use, e.g. 'REDIS_7' + * @returns Cache connection properties + */ + async init( + id: TestCacheId, + ): Promise<{ store: string; connection: string; keyv: Keyv }> { + const properties = allCaches[id]; + if (!properties) { + const candidates = Object.keys(allCaches).join(', '); + throw new Error( + `Unknown test cache ${id}, possible values are ${candidates}`, + ); + } + if (!this.supportedIds.includes(id)) { + const candidates = this.supportedIds.join(', '); + throw new Error( + `Unsupported test cache ${id} for this environment, possible values are ${candidates}`, + ); + } + + // Ensure that a testcontainers instance is up for this ID + let instance: Instance | undefined = this.instanceById.get(id); + if (!instance) { + instance = await this.initAny(properties); + this.instanceById.set(id, instance); + } + + // Ensure that it's cleared of data from previous tests + await instance.keyv.clear(); + + return { + store: instance.store, + connection: instance.connection, + keyv: instance.keyv, + }; + } + + private async initAny(properties: TestCacheProperties): Promise { + switch (properties.store) { + case 'memcache': + return this.initMemcached(properties); + case 'redis': + return this.initRedis(properties); + case 'memory': + return { + store: 'memory', + connection: 'memory', + keyv: new Keyv(), + stop: async () => {}, + }; + default: + throw new Error(`Unknown cache store '${properties.store}'`); + } + } + + private async initMemcached( + properties: TestCacheProperties, + ): Promise { + // Use the connection string if provided + const envVarName = properties.connectionStringEnvironmentVariableName; + if (envVarName) { + const connectionString = process.env[envVarName]; + if (connectionString) { + return connectToExternalMemcache(connectionString); + } + } + + return await startMemcachedContainer(properties.dockerImageName!); + } + + private async initRedis(properties: TestCacheProperties): Promise { + // Use the connection string if provided + const envVarName = properties.connectionStringEnvironmentVariableName; + if (envVarName) { + const connectionString = process.env[envVarName]; + if (connectionString) { + return connectToExternalRedis(connectionString); + } + } + + return await startRedisContainer(properties.dockerImageName!); + } + + private async shutdown() { + const instances = [...this.instanceById.values()]; + this.instanceById.clear(); + await Promise.all( + instances.map(({ stop }) => + stop().catch(error => { + console.warn(`TestCaches: Failed to stop container`, { error }); + }), + ), + ); + } +} diff --git a/packages/backend-test-utils/src/cache/index.ts b/packages/backend-test-utils/src/cache/index.ts new file mode 100644 index 0000000000..46d95545bf --- /dev/null +++ b/packages/backend-test-utils/src/cache/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { TestCaches } from './TestCaches'; +export type { TestCacheId } from './types'; diff --git a/packages/backend-test-utils/src/database/startMysqlContainer.test.ts b/packages/backend-test-utils/src/cache/memcache.test.ts similarity index 58% rename from packages/backend-test-utils/src/database/startMysqlContainer.test.ts rename to packages/backend-test-utils/src/cache/memcache.test.ts index 23cb128a35..bd912ce9d2 100644 --- a/packages/backend-test-utils/src/database/startMysqlContainer.test.ts +++ b/packages/backend-test-utils/src/cache/memcache.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,21 @@ * limitations under the License. */ -import createConnection from 'knex'; import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; -import { startMysqlContainer } from './startMysqlContainer'; +import { startMemcachedContainer } from './memcache'; +import { v4 as uuid } from 'uuid'; const itIfDocker = isDockerDisabledForTests() ? it.skip : it; jest.setTimeout(60_000); -describe('startMysqlContainer', () => { +describe('startMemcachedContainer', () => { itIfDocker('successfully launches the container', async () => { - const { stop, ...connection } = await startMysqlContainer('mysql:8'); - const db = createConnection({ client: 'mysql2', connection }); - try { - const result = await db.select(db.raw('version() AS version')); - // eslint-disable-next-line jest/no-standalone-expect - expect(result[0]?.version).toContain('8.'); - } finally { - await db.destroy(); - await stop(); - } + const { stop, keyv } = await startMemcachedContainer('memcached:1'); + const value = uuid(); + await keyv.set('test', value); + // eslint-disable-next-line jest/no-standalone-expect + await expect(keyv.get('test')).resolves.toBe(value); + await stop(); }); }); diff --git a/packages/backend-test-utils/src/cache/memcache.ts b/packages/backend-test-utils/src/cache/memcache.ts new file mode 100644 index 0000000000..b7ac07cb13 --- /dev/null +++ b/packages/backend-test-utils/src/cache/memcache.ts @@ -0,0 +1,83 @@ +/* + * 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 Keyv from 'keyv'; +import KeyvMemcache from '@keyv/memcache'; +import { v4 as uuid } from 'uuid'; +import { Instance } from './types'; + +async function attemptMemcachedConnection(connection: string): Promise { + const startTime = Date.now(); + + for (;;) { + try { + const store = new KeyvMemcache(connection); + const keyv = new Keyv({ store }); + const value = uuid(); + await keyv.set('test', value); + if ((await keyv.get('test')) === value) { + return keyv; + } + } catch (e) { + if (Date.now() - startTime > 30_000) { + throw new Error( + `Timed out waiting for memcached to be ready for connections, ${e}`, + ); + } + } + + await new Promise(resolve => setTimeout(resolve, 100)); + } +} + +export async function connectToExternalMemcache( + connection: string, +): Promise { + const keyv = await attemptMemcachedConnection(connection); + return { + store: 'memcache', + connection, + keyv, + stop: async () => await keyv.disconnect(), + }; +} + +export async function startMemcachedContainer( + image: string, +): Promise { + // Lazy-load to avoid side-effect of importing testcontainers + const { GenericContainer } = await import('testcontainers'); + + const container = await new GenericContainer(image) + .withExposedPorts(11211) + .start(); + + const host = container.getHost(); + const port = container.getMappedPort(11211); + const connection = `${host}:${port}`; + + const keyv = await attemptMemcachedConnection(connection); + + return { + store: 'memcache', + connection, + keyv, + stop: async () => { + await keyv.disconnect(); + await container.stop({ timeout: 10_000 }); + }, + }; +} diff --git a/packages/backend-test-utils/src/database/startPostgresContainer.test.ts b/packages/backend-test-utils/src/cache/redis.test.ts similarity index 57% rename from packages/backend-test-utils/src/database/startPostgresContainer.test.ts rename to packages/backend-test-utils/src/cache/redis.test.ts index f64a605fd4..6555a26677 100644 --- a/packages/backend-test-utils/src/database/startPostgresContainer.test.ts +++ b/packages/backend-test-utils/src/cache/redis.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,21 @@ * limitations under the License. */ -import createConnection from 'knex'; import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; -import { startPostgresContainer } from './startPostgresContainer'; +import { startRedisContainer } from './redis'; +import { v4 as uuid } from 'uuid'; const itIfDocker = isDockerDisabledForTests() ? it.skip : it; jest.setTimeout(60_000); -describe('startPostgresContainer', () => { +describe('startRedisContainer', () => { itIfDocker('successfully launches the container', async () => { - const { stop, ...connection } = await startPostgresContainer('postgres:13'); - const db = createConnection({ client: 'pg', connection }); - try { - const result = await db.select(db.raw('version()')); - // eslint-disable-next-line jest/no-standalone-expect - expect(result[0]?.version).toContain('PostgreSQL'); - } finally { - await db.destroy(); - await stop(); - } + const { stop, keyv } = await startRedisContainer('redis:7'); + const value = uuid(); + await keyv.set('test', value); + // eslint-disable-next-line jest/no-standalone-expect + await expect(keyv.get('test')).resolves.toBe(value); + await stop(); }); }); diff --git a/packages/backend-test-utils/src/cache/redis.ts b/packages/backend-test-utils/src/cache/redis.ts new file mode 100644 index 0000000000..6185e4d076 --- /dev/null +++ b/packages/backend-test-utils/src/cache/redis.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Keyv from 'keyv'; +import KeyvRedis from '@keyv/redis'; +import { v4 as uuid } from 'uuid'; +import { Instance } from './types'; + +async function attemptRedisConnection(connection: string): Promise { + const startTime = Date.now(); + + for (;;) { + try { + const store = new KeyvRedis(connection); + const keyv = new Keyv({ store }); + const value = uuid(); + await keyv.set('test', value); + if ((await keyv.get('test')) === value) { + return keyv; + } + } catch (e) { + if (Date.now() - startTime > 30_000) { + throw new Error( + `Timed out waiting for redis to be ready for connections, ${e}`, + ); + } + } + + await new Promise(resolve => setTimeout(resolve, 100)); + } +} + +export async function connectToExternalRedis( + connection: string, +): Promise { + const keyv = await attemptRedisConnection(connection); + return { + store: 'redis', + connection, + keyv, + stop: async () => await keyv.disconnect(), + }; +} + +export async function startRedisContainer(image: string): Promise { + // Lazy-load to avoid side-effect of importing testcontainers + const { GenericContainer } = await import('testcontainers'); + + const container = await new GenericContainer(image) + .withExposedPorts(6379) + .start(); + + const host = container.getHost(); + const port = container.getMappedPort(6379); + const connection = `redis://${host}:${port}`; + + const keyv = await attemptRedisConnection(connection); + + return { + store: 'redis', + connection, + keyv, + stop: async () => { + await keyv.disconnect(); + await container.stop({ timeout: 10_000 }); + }, + }; +} diff --git a/packages/backend-test-utils/src/cache/types.ts b/packages/backend-test-utils/src/cache/types.ts new file mode 100644 index 0000000000..1aea522042 --- /dev/null +++ b/packages/backend-test-utils/src/cache/types.ts @@ -0,0 +1,61 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Keyv from 'keyv'; +import { getDockerImageForName } from '../util/getDockerImageForName'; + +/** + * The possible caches to test against. + * + * @public + */ +export type TestCacheId = 'MEMORY' | 'REDIS_7' | 'MEMCACHED_1'; + +export type TestCacheProperties = { + name: string; + store: string; + dockerImageName?: string; + connectionStringEnvironmentVariableName?: string; +}; + +export type Instance = { + store: string; + connection: string; + keyv: Keyv; + stop: () => Promise; +}; + +export const allCaches: Record = + Object.freeze({ + REDIS_7: { + name: 'Redis 7.x', + store: 'redis', + dockerImageName: getDockerImageForName('redis:7'), + connectionStringEnvironmentVariableName: + 'BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING', + }, + MEMCACHED_1: { + name: 'Memcached 1.x', + store: 'memcache', + dockerImageName: getDockerImageForName('memcached:1'), + connectionStringEnvironmentVariableName: + 'BACKSTAGE_TEST_CACHE_MEMCACHED1_CONNECTION_STRING', + }, + MEMORY: { + name: 'In-memory', + store: 'memory', + }, + }); diff --git a/packages/backend-test-utils/src/database/TestDatabases.test.ts b/packages/backend-test-utils/src/database/TestDatabases.test.ts index 64e4d76443..fea7189aec 100644 --- a/packages/backend-test-utils/src/database/TestDatabases.test.ts +++ b/packages/backend-test-utils/src/database/TestDatabases.test.ts @@ -14,28 +14,11 @@ * limitations under the License. */ -import knexFactory from 'knex'; -import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; -import { startMysqlContainer } from './startMysqlContainer'; -import { startPostgresContainer } from './startPostgresContainer'; import { TestDatabases } from './TestDatabases'; -const itIfDocker = isDockerDisabledForTests() ? it.skip : it; - jest.setTimeout(60_000); describe('TestDatabases', () => { - const OLD_ENV = process.env; - - beforeEach(() => { - jest.resetModules(); - process.env = { ...OLD_ENV }; - }); - - afterAll(() => { - process.env = OLD_ENV; - }); - describe('each create', () => { const dbs = TestDatabases.create(); @@ -55,254 +38,4 @@ describe('TestDatabases', () => { }, ); }); - - describe('each connect', () => { - const dbs = TestDatabases.create(); - - itIfDocker( - 'obeys a provided connection string for postgres 16', - async () => { - const { host, port, user, password, stop } = - await startPostgresContainer('postgres:16'); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_POSTGRES16_CONNECTION_STRING = `postgresql://${user}:${password}@${host}:${port}`; - const input = await dbs.init('POSTGRES_16'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'pg', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }, - ); - - itIfDocker( - 'obeys a provided connection string for postgres 15', - async () => { - const { host, port, user, password, stop } = - await startPostgresContainer('postgres:15'); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_POSTGRES15_CONNECTION_STRING = `postgresql://${user}:${password}@${host}:${port}`; - const input = await dbs.init('POSTGRES_15'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'pg', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }, - ); - - itIfDocker( - 'obeys a provided connection string for postgres 14', - async () => { - const { host, port, user, password, stop } = - await startPostgresContainer('postgres:14'); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_POSTGRES14_CONNECTION_STRING = `postgresql://${user}:${password}@${host}:${port}`; - const input = await dbs.init('POSTGRES_14'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'pg', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }, - ); - - itIfDocker( - 'obeys a provided connection string for postgres 13', - async () => { - const { host, port, user, password, stop } = - await startPostgresContainer('postgres:13'); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_POSTGRES13_CONNECTION_STRING = `postgresql://${user}:${password}@${host}:${port}`; - const input = await dbs.init('POSTGRES_13'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'pg', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }, - ); - - itIfDocker( - 'obeys a provided connection string for postgres 12', - async () => { - const { host, port, user, password, stop } = - await startPostgresContainer('postgres:12'); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_POSTGRES12_CONNECTION_STRING = `postgresql://${user}:${password}@${host}:${port}`; - const input = await dbs.init('POSTGRES_12'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'pg', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }, - ); - - itIfDocker( - 'obeys a provided connection string for postgres 11', - async () => { - const { host, port, user, password, stop } = - await startPostgresContainer('postgres:11'); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_POSTGRES11_CONNECTION_STRING = `postgresql://${user}:${password}@${host}:${port}`; - const input = await dbs.init('POSTGRES_11'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'pg', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }, - ); - - itIfDocker( - 'obeys a provided connection string for postgres 9', - async () => { - const { host, port, user, password, stop } = - await startPostgresContainer('postgres:9'); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING = `postgresql://${user}:${password}@${host}:${port}`; - const input = await dbs.init('POSTGRES_9'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'pg', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }, - ); - - itIfDocker('obeys a provided connection string for mysql 8', async () => { - const { host, port, user, password, stop } = await startMysqlContainer( - 'mysql:8', - ); - - try { - // Leave a mark - process.env.BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING = `mysql://${user}:${password}@${host}:${port}/ignored`; - const input = await dbs.init('MYSQL_8'); - await input.schema.createTable('a', table => - table.string('x').primary(), - ); - await input.insert({ x: 'y' }).into('a'); - - // Look for the mark - const database = input.client.config.connection.database; - const output = knexFactory({ - client: 'mysql2', - connection: { host, port, user, password, database }, - }); - // eslint-disable-next-line jest/no-standalone-expect - await expect(output.select('x').from('a')).resolves.toEqual([ - { x: 'y' }, - ]); - } finally { - await stop(); - } - }); - }); }); diff --git a/packages/backend-test-utils/src/database/TestDatabases.ts b/packages/backend-test-utils/src/database/TestDatabases.ts index 4ea8fe05d7..cd20e2997b 100644 --- a/packages/backend-test-utils/src/database/TestDatabases.ts +++ b/packages/backend-test-utils/src/database/TestDatabases.ts @@ -14,27 +14,18 @@ * limitations under the License. */ -import { DatabaseManager, dropDatabase } from '@backstage/backend-common'; -import { ConfigReader } from '@backstage/config'; -import { randomBytes } from 'crypto'; import { Knex } from 'knex'; import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; -import { startMysqlContainer } from './startMysqlContainer'; -import { startPostgresContainer } from './startPostgresContainer'; +import { MysqlEngine } from './mysql'; +import { PostgresEngine } from './postgres'; +import { SqliteEngine } from './sqlite'; import { - allDatabases, - Instance, + Engine, TestDatabaseId, TestDatabaseProperties, + allDatabases, } from './types'; -const LARGER_POOL_CONFIG = { - pool: { - min: 0, - max: 50, - }, -}; - /** * Encapsulates the creation of ephemeral test database instances for use * inside unit or integration tests. @@ -42,7 +33,17 @@ const LARGER_POOL_CONFIG = { * @public */ export class TestDatabases { - private readonly instanceById: Map; + private readonly engineFactoryByDriver: Record< + string, + (properties: TestDatabaseProperties) => Promise + > = { + pg: PostgresEngine.create, + mysql: MysqlEngine.create, + mysql2: MysqlEngine.create, + 'better-sqlite3': SqliteEngine.create, + sqlite3: SqliteEngine.create, + }; + private readonly engineByTestDatabaseId: Map; private readonly supportedIds: TestDatabaseId[]; private static defaultIds?: TestDatabaseId[]; @@ -114,7 +115,7 @@ export class TestDatabases { } private constructor(supportedIds: TestDatabaseId[]) { - this.instanceById = new Map(); + this.engineByTestDatabaseId = new Map(); this.supportedIds = supportedIds; } @@ -148,185 +149,29 @@ export class TestDatabases { ); } - let instance: Instance | undefined = this.instanceById.get(id); - - // Ensure that a testcontainers instance is up for this ID - if (!instance) { - instance = await this.initAny(properties); - this.instanceById.set(id, instance); - } - - // Ensure that a unique logical database is created in the instance - const databaseName = `db${randomBytes(16).toString('hex')}`; - const connection = await instance.databaseManager - .forPlugin(databaseName) - .getClient(); - - instance.connections.push(connection); - instance.databaseNames.push(databaseName); - - return connection; - } - - private async initAny(properties: TestDatabaseProperties): Promise { - // Use the connection string if provided - if (properties.driver === 'pg' || properties.driver === 'mysql2') { - const envVarName = properties.connectionStringEnvironmentVariableName; - if (envVarName) { - const connectionString = process.env[envVarName]; - if (connectionString) { - const config = new ConfigReader({ - backend: { - database: { - knexConfig: properties.driver.includes('sqlite') - ? {} - : LARGER_POOL_CONFIG, - client: properties.driver, - connection: connectionString, - }, - }, - }); - const databaseManager = DatabaseManager.fromConfig(config); - const databaseNames: Array = []; - return { - dropDatabases: async () => { - await dropDatabase( - config.getConfig('backend.database'), - ...databaseNames.map( - databaseName => `backstage_plugin_${databaseName}`, - ), - ); - }, - databaseManager, - databaseNames, - connections: [], - }; - } - } - } - - // Otherwise start a container for the purpose - switch (properties.driver) { - case 'pg': - return this.initPostgres(properties); - case 'mysql2': - return this.initMysql(properties); - case 'better-sqlite3': - case 'sqlite3': - return this.initSqlite(properties); - default: + let engine = this.engineByTestDatabaseId.get(id); + if (!engine) { + const factory = this.engineFactoryByDriver[properties.driver]; + if (!factory) { throw new Error(`Unknown database driver ${properties.driver}`); + } + engine = await factory(properties); + this.engineByTestDatabaseId.set(id, engine); } - } - private async initPostgres( - properties: TestDatabaseProperties, - ): Promise { - const { host, port, user, password, stop } = await startPostgresContainer( - properties.dockerImageName!, - ); - - const databaseManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - knexConfig: LARGER_POOL_CONFIG, - client: 'pg', - connection: { host, port, user, password }, - }, - }, - }), - ); - return { - stopContainer: stop, - databaseManager, - databaseNames: [], - connections: [], - }; - } - - private async initMysql( - properties: TestDatabaseProperties, - ): Promise { - const { host, port, user, password, stop } = await startMysqlContainer( - properties.dockerImageName!, - ); - - const databaseManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - knexConfig: LARGER_POOL_CONFIG, - client: 'mysql2', - connection: { host, port, user, password }, - }, - }, - }), - ); - - return { - stopContainer: stop, - databaseManager, - databaseNames: [], - connections: [], - }; - } - - private async initSqlite( - properties: TestDatabaseProperties, - ): Promise { - const databaseManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: properties.driver, - connection: ':memory:', - }, - }, - }), - ); - return { - databaseManager, - databaseNames: [], - connections: [], - }; + return await engine.createDatabaseInstance(); } private async shutdown() { - const instances = [...this.instanceById.values()]; - this.instanceById.clear(); + const engines = [...this.engineByTestDatabaseId.values()]; + this.engineByTestDatabaseId.clear(); - for (const { - stopContainer, - dropDatabases, - connections, - databaseManager, - } of instances) { - for (const connection of connections) { - try { - await connection.destroy(); - } catch (error) { - console.warn(`TestDatabases: Failed to destroy connection`, { - connection, - error, - }); - } - } - - // If the database is not running in docker then drop the databases + for (const engine of engines) { try { - await dropDatabases?.(); + await engine.shutdown(); } catch (error) { - console.warn(`TestDatabases: Failed to drop databases`, { - error, - }); - } - - try { - await stopContainer?.(); - } catch (error) { - console.warn(`TestDatabases: Failed to stop container`, { - databaseManager, + console.warn(`TestDatabases: Failed to shutdown engine`, { + engine, error, }); } diff --git a/packages/backend-test-utils/src/database/index.ts b/packages/backend-test-utils/src/database/index.ts index 69e3f41452..949553cef2 100644 --- a/packages/backend-test-utils/src/database/index.ts +++ b/packages/backend-test-utils/src/database/index.ts @@ -14,6 +14,5 @@ * limitations under the License. */ -export { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; export { TestDatabases } from './TestDatabases'; export type { TestDatabaseId } from './types'; diff --git a/packages/backend-test-utils/src/database/mysql.test.ts b/packages/backend-test-utils/src/database/mysql.test.ts new file mode 100644 index 0000000000..a5b6b854f3 --- /dev/null +++ b/packages/backend-test-utils/src/database/mysql.test.ts @@ -0,0 +1,113 @@ +/* + * 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 knexFactory, { Knex } from 'knex'; +import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; +import { MysqlEngine, startMysqlContainer } from './mysql'; +import { Engine, TestDatabaseId, allDatabases } from './types'; + +const itIfDocker = isDockerDisabledForTests() ? it.skip : it; +const ourDatabaseIds = Object.entries(allDatabases) + .filter(([, properties]) => properties.driver.includes('mysql')) + .map(([id]) => id as TestDatabaseId); + +jest.setTimeout(60_000); + +describe('startMysqlContainer', () => { + itIfDocker( + 'successfully launches the container and can stop it without problems', + async () => { + const { connection, stopContainer } = await startMysqlContainer( + 'mysql:8', + ); + const db = knexFactory({ client: 'mysql2', connection }); + try { + const result = await db.select(db.raw('version() AS version')); + // eslint-disable-next-line jest/no-standalone-expect + expect(result[0]?.version).toContain('8.'); + } finally { + await db.destroy(); + await stopContainer(); + } + }, + ); +}); + +describe('MysqlEngine', () => { + const OLD_ENV = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = { ...OLD_ENV }; + }); + + afterAll(() => { + process.env = OLD_ENV; + }); + + itIfDocker.each(ourDatabaseIds)( + 'uses given connection string, %p', + async testDatabaseId => { + const properties = allDatabases[testDatabaseId]; + const { connection } = await startMysqlContainer( + properties.dockerImageName!, + ); + + const outerKnex = knexFactory({ client: properties.driver, connection }); + const databases = await outerKnex + .raw('SHOW DATABASES') + .then(rows => rows[0].length); // account for meta databases, if any + + let knex: Knex | undefined; + let engine: Engine | undefined; + try { + process.env[ + properties.connectionStringEnvironmentVariableName! + ] = `mysql://${connection.user}:${connection.password}@${connection.host}:${connection.port}/ignored`; + engine = await MysqlEngine.create(properties); + knex = await engine.createDatabaseInstance(); + + // eslint-disable-next-line jest/no-standalone-expect + await expect( + outerKnex.raw('SHOW DATABASES').then(rows => rows[0].length), + ).resolves.toBe(databases + 1); + } finally { + await outerKnex.destroy(); + await knex?.destroy(); + await engine?.shutdown(); + } + }, + ); + + itIfDocker.each(ourDatabaseIds)( + 'creates docker containers, %p', + async testDatabaseId => { + const properties = allDatabases[testDatabaseId]; + delete process.env[properties.connectionStringEnvironmentVariableName!]; + const engine = await MysqlEngine.create(properties); + + try { + const knex = await engine.createDatabaseInstance(); + // eslint-disable-next-line jest/no-standalone-expect + await expect( + knex.select(knex.raw('version() as version')), + ).resolves.toEqual([{ version: expect.any(String) }]); + } finally { + await engine.shutdown(); + } + }, + ); +}); diff --git a/packages/backend-test-utils/src/database/mysql.ts b/packages/backend-test-utils/src/database/mysql.ts new file mode 100644 index 0000000000..ab130dc5c8 --- /dev/null +++ b/packages/backend-test-utils/src/database/mysql.ts @@ -0,0 +1,242 @@ +/* + * 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 { stringifyError } from '@backstage/errors'; +import { randomBytes } from 'crypto'; +import knexFactory, { Knex } from 'knex'; +import { v4 as uuid } from 'uuid'; +import yn from 'yn'; +import { Engine, LARGER_POOL_CONFIG, TestDatabaseProperties } from './types'; + +async function waitForMysqlReady( + connection: Knex.MySqlConnectionConfig, +): Promise { + const startTime = Date.now(); + + let lastError: Error | undefined; + let attempts = 0; + for (;;) { + attempts += 1; + + let knex: Knex | undefined; + try { + knex = knexFactory({ + client: 'mysql2', + connection: { + // make a copy because the driver mutates this + ...connection, + }, + }); + const result = await knex.select(knex.raw('version() AS version')); + if (Array.isArray(result) && result[0]?.version) { + return; + } + } catch (e) { + lastError = e; + } finally { + await knex?.destroy(); + } + + if (Date.now() - startTime > 30_000) { + throw new Error( + `Timed out waiting for the database to be ready for connections, ${attempts} attempts, ${ + lastError + ? `last error was ${stringifyError(lastError)}` + : '(no errors thrown)' + }`, + ); + } + + await new Promise(resolve => setTimeout(resolve, 100)); + } +} + +export async function startMysqlContainer(image: string): Promise<{ + connection: Knex.MySqlConnectionConfig; + stopContainer: () => Promise; +}> { + const user = 'root'; + const password = uuid(); + + // Lazy-load to avoid side-effect of importing testcontainers + const { GenericContainer } = await import('testcontainers'); + + const container = await new GenericContainer(image) + .withExposedPorts(3306) + .withEnvironment({ MYSQL_ROOT_PASSWORD: password }) + .withTmpFs({ '/var/lib/mysql': 'rw' }) + .start(); + + const host = container.getHost(); + const port = container.getMappedPort(3306); + const connection = { host, port, user, password }; + const stopContainer = async () => { + await container.stop({ timeout: 10_000 }); + }; + + await waitForMysqlReady(connection); + + return { connection, stopContainer }; +} + +export function parseMysqlConnectionString( + connectionString: string, +): Knex.MySqlConnectionConfig { + try { + const { + protocol, + username, + password, + port, + hostname, + pathname, + searchParams, + } = new URL(connectionString); + + if (protocol !== 'mysql:') { + throw new Error(`Unknown protocol ${protocol}`); + } else if (!username || !password) { + throw new Error(`Missing username/password`); + } else if (!pathname.match(/^\/[^/]+$/)) { + throw new Error(`Expected single path segment`); + } + + const result: Knex.MySqlConnectionConfig = { + user: username, + password, + host: hostname, + port: Number(port || 3306), + database: decodeURIComponent(pathname.substring(1)), + }; + + const ssl = searchParams.get('ssl'); + if (ssl) { + result.ssl = ssl; + } + + const debug = searchParams.get('debug'); + if (debug) { + result.debug = yn(debug); + } + + return result; + } catch (e) { + throw new Error(`Error while parsing MySQL connection string, ${e}`, e); + } +} + +export class MysqlEngine implements Engine { + static async create( + properties: TestDatabaseProperties, + ): Promise { + const { connectionStringEnvironmentVariableName, dockerImageName } = + properties; + + if (connectionStringEnvironmentVariableName) { + const connectionString = + process.env[connectionStringEnvironmentVariableName]; + if (connectionString) { + const connection = parseMysqlConnectionString(connectionString); + return new MysqlEngine( + properties, + connection as Knex.MySqlConnectionConfig, + ); + } + } + + if (dockerImageName) { + const { connection, stopContainer } = await startMysqlContainer( + dockerImageName, + ); + return new MysqlEngine(properties, connection, stopContainer); + } + + throw new Error(`Test databasee for ${properties.name} not configured`); + } + + readonly #properties: TestDatabaseProperties; + readonly #connection: Knex.MySqlConnectionConfig; + readonly #knexInstances: Knex[]; + readonly #databaseNames: string[]; + readonly #stopContainer?: () => Promise; + + constructor( + properties: TestDatabaseProperties, + connection: Knex.MySqlConnectionConfig, + stopContainer?: () => Promise, + ) { + this.#properties = properties; + this.#connection = connection; + this.#knexInstances = []; + this.#databaseNames = []; + this.#stopContainer = stopContainer; + } + + async createDatabaseInstance(): Promise { + const adminConnection = this.#connectAdmin(); + try { + const databaseName = `db${randomBytes(16).toString('hex')}`; + + await adminConnection.raw('CREATE DATABASE ??', [databaseName]); + this.#databaseNames.push(databaseName); + + const knexInstance = knexFactory({ + client: this.#properties.driver, + connection: { + ...this.#connection, + database: databaseName, + }, + ...LARGER_POOL_CONFIG, + }); + this.#knexInstances.push(knexInstance); + + return knexInstance; + } finally { + await adminConnection.destroy(); + } + } + + async shutdown(): Promise { + for (const instance of this.#knexInstances) { + await instance.destroy(); + } + + const adminConnection = this.#connectAdmin(); + try { + for (const databaseName of this.#databaseNames) { + await adminConnection.raw('DROP DATABASE ??', [databaseName]); + } + } finally { + await adminConnection.destroy(); + } + + await this.#stopContainer?.(); + } + + #connectAdmin(): Knex { + const connection = { + ...this.#connection, + database: null as unknown as string, + }; + return knexFactory({ + client: this.#properties.driver, + connection, + pool: { + acquireTimeoutMillis: 10000, + }, + }); + } +} diff --git a/packages/backend-test-utils/src/database/postgres.test.ts b/packages/backend-test-utils/src/database/postgres.test.ts new file mode 100644 index 0000000000..3d0d7b041b --- /dev/null +++ b/packages/backend-test-utils/src/database/postgres.test.ts @@ -0,0 +1,113 @@ +/* + * 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 knexFactory, { Knex } from 'knex'; +import { isDockerDisabledForTests } from '../util/isDockerDisabledForTests'; +import { startPostgresContainer, PostgresEngine } from './postgres'; +import { Engine, TestDatabaseId, allDatabases } from './types'; + +const itIfDocker = isDockerDisabledForTests() ? it.skip : it; +const ourDatabaseIds = Object.entries(allDatabases) + .filter(([, properties]) => properties.driver === 'pg') + .map(([id]) => id as TestDatabaseId); + +jest.setTimeout(60_000); + +describe('startPostgresContainer', () => { + itIfDocker( + 'successfully launches the container and can stop it without problems', + async () => { + const { connection, stopContainer } = await startPostgresContainer( + 'postgres:13', + ); + const db = knexFactory({ client: 'pg', connection }); + try { + const result = await db.select(db.raw('version()')); + // eslint-disable-next-line jest/no-standalone-expect + expect(result[0]?.version).toContain('PostgreSQL'); + } finally { + await db.destroy(); + await stopContainer(); + } + }, + ); +}); + +describe('PostgresEngine', () => { + const OLD_ENV = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = { ...OLD_ENV }; + }); + + afterAll(() => { + process.env = OLD_ENV; + }); + + itIfDocker.each(ourDatabaseIds)( + 'uses given connection string, %p', + async testDatabaseId => { + const properties = allDatabases[testDatabaseId]; + const { connection } = await startPostgresContainer( + properties.dockerImageName!, + ); + + const outerKnex = knexFactory({ client: properties.driver, connection }); + const databases = await outerKnex + .from('pg_database') + .then(rows => rows.length); // account for postgres, template0 etc + + let knex: Knex | undefined; + let engine: Engine | undefined; + try { + process.env[ + properties.connectionStringEnvironmentVariableName! + ] = `postgres://${connection.user}:${connection.password}@${connection.host}:${connection.port}`; + engine = await PostgresEngine.create(properties); + knex = await engine.createDatabaseInstance(); + + // eslint-disable-next-line jest/no-standalone-expect + await expect(outerKnex.from('pg_database')).resolves.toHaveLength( + databases + 1, + ); + } finally { + await outerKnex.destroy(); + await knex?.destroy(); + await engine?.shutdown(); + } + }, + ); + + itIfDocker.each(ourDatabaseIds)( + 'creates docker containers, %p', + async testDatabaseId => { + const properties = allDatabases[testDatabaseId]; + delete process.env[properties.connectionStringEnvironmentVariableName!]; + const engine = await PostgresEngine.create(properties); + + try { + const knex = await engine.createDatabaseInstance(); + // eslint-disable-next-line jest/no-standalone-expect + await expect(knex.select(knex.raw('version()'))).resolves.toEqual([ + { version: expect.stringContaining('PostgreSQL') }, + ]); + } finally { + await engine.shutdown(); + } + }, + ); +}); diff --git a/packages/backend-test-utils/src/database/postgres.ts b/packages/backend-test-utils/src/database/postgres.ts new file mode 100644 index 0000000000..c8a946d121 --- /dev/null +++ b/packages/backend-test-utils/src/database/postgres.ts @@ -0,0 +1,195 @@ +/* + * 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 { stringifyError } from '@backstage/errors'; +import { randomBytes } from 'crypto'; +import knexFactory, { Knex } from 'knex'; +import { parse as parsePgConnectionString } from 'pg-connection-string'; +import { v4 as uuid } from 'uuid'; +import { Engine, LARGER_POOL_CONFIG, TestDatabaseProperties } from './types'; + +async function waitForPostgresReady( + connection: Knex.PgConnectionConfig, +): Promise { + const startTime = Date.now(); + + let lastError: Error | undefined; + let attempts = 0; + for (;;) { + attempts += 1; + + let knex: Knex | undefined; + try { + knex = knexFactory({ + client: 'pg', + connection: { + // make a copy because the driver mutates this + ...connection, + }, + }); + const result = await knex.select(knex.raw('version()')); + if (Array.isArray(result) && result[0]?.version) { + return; + } + } catch (e) { + lastError = e; + } finally { + await knex?.destroy(); + } + + if (Date.now() - startTime > 30_000) { + throw new Error( + `Timed out waiting for the database to be ready for connections, ${attempts} attempts, ${ + lastError + ? `last error was ${stringifyError(lastError)}` + : '(no errors thrown)' + }`, + ); + } + + await new Promise(resolve => setTimeout(resolve, 100)); + } +} + +export async function startPostgresContainer(image: string): Promise<{ + connection: Knex.PgConnectionConfig; + stopContainer: () => Promise; +}> { + const user = 'postgres'; + const password = uuid(); + + // Lazy-load to avoid side-effect of importing testcontainers + const { GenericContainer } = await import('testcontainers'); + + const container = await new GenericContainer(image) + .withExposedPorts(5432) + .withEnvironment({ POSTGRES_PASSWORD: password }) + .withTmpFs({ '/var/lib/postgresql/data': 'rw' }) + .start(); + + const host = container.getHost(); + const port = container.getMappedPort(5432); + const connection = { host, port, user, password }; + const stopContainer = async () => { + await container.stop({ timeout: 10_000 }); + }; + + await waitForPostgresReady(connection); + + return { connection, stopContainer }; +} + +export class PostgresEngine implements Engine { + static async create( + properties: TestDatabaseProperties, + ): Promise { + const { connectionStringEnvironmentVariableName, dockerImageName } = + properties; + + if (connectionStringEnvironmentVariableName) { + const connectionString = + process.env[connectionStringEnvironmentVariableName]; + if (connectionString) { + const connection = parsePgConnectionString(connectionString); + return new PostgresEngine( + properties, + connection as Knex.PgConnectionConfig, + ); + } + } + + if (dockerImageName) { + const { connection, stopContainer } = await startPostgresContainer( + dockerImageName, + ); + return new PostgresEngine(properties, connection, stopContainer); + } + + throw new Error(`Test databasee for ${properties.name} not configured`); + } + + readonly #properties: TestDatabaseProperties; + readonly #connection: Knex.PgConnectionConfig; + readonly #knexInstances: Knex[]; + readonly #databaseNames: string[]; + readonly #stopContainer?: () => Promise; + + constructor( + properties: TestDatabaseProperties, + connection: Knex.PgConnectionConfig, + stopContainer?: () => Promise, + ) { + this.#properties = properties; + this.#connection = connection; + this.#knexInstances = []; + this.#databaseNames = []; + this.#stopContainer = stopContainer; + } + + async createDatabaseInstance(): Promise { + const adminConnection = this.#connectAdmin(); + try { + const databaseName = `db${randomBytes(16).toString('hex')}`; + + await adminConnection.raw('CREATE DATABASE ??', [databaseName]); + this.#databaseNames.push(databaseName); + + const knexInstance = knexFactory({ + client: this.#properties.driver, + connection: { + ...this.#connection, + database: databaseName, + }, + ...LARGER_POOL_CONFIG, + }); + this.#knexInstances.push(knexInstance); + + return knexInstance; + } finally { + await adminConnection.destroy(); + } + } + + async shutdown(): Promise { + for (const instance of this.#knexInstances) { + await instance.destroy(); + } + + const adminConnection = this.#connectAdmin(); + try { + for (const databaseName of this.#databaseNames) { + await adminConnection.raw('DROP DATABASE ??', [databaseName]); + } + } finally { + await adminConnection.destroy(); + } + + await this.#stopContainer?.(); + } + + #connectAdmin(): Knex { + return knexFactory({ + client: this.#properties.driver, + connection: { + ...this.#connection, + database: 'postgres', + }, + pool: { + acquireTimeoutMillis: 10000, + }, + }); + } +} diff --git a/packages/backend-test-utils/src/database/sqlite.test.ts b/packages/backend-test-utils/src/database/sqlite.test.ts new file mode 100644 index 0000000000..8eca09a698 --- /dev/null +++ b/packages/backend-test-utils/src/database/sqlite.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SqliteEngine } from './sqlite'; +import { TestDatabaseId, allDatabases } from './types'; + +const ourDatabaseIds = Object.entries(allDatabases) + .filter(([, properties]) => properties.driver.includes('sqlite')) + .map(([id]) => id as TestDatabaseId); + +describe('SqliteEngine', () => { + it.each(ourDatabaseIds)( + 'should create a database instance, %p', + async testDatabaseId => { + for (let i = 0; i < 100; ++i) { + const properties = allDatabases[testDatabaseId]; + const engine = await SqliteEngine.create(properties); + + const instance1 = await engine.createDatabaseInstance(); + const instance2 = await engine.createDatabaseInstance(); + expect(instance1).toBeDefined(); + expect(instance2).toBeDefined(); + expect(instance1).not.toEqual(instance2); + + await instance1.schema.createTable('t', table => { + table.string('value'); + }); + await instance2.schema.createTable('t', table => { + table.string('value'); + }); + + await instance1('t').insert({ value: 'value1' }); + await instance2('t').insert({ value: 'value2' }); + + await expect(instance1('t')).resolves.toEqual([{ value: 'value1' }]); + await expect(instance2('t')).resolves.toEqual([{ value: 'value2' }]); + + await engine.shutdown(); + } + }, + ); +}); diff --git a/packages/backend-test-utils/src/database/sqlite.ts b/packages/backend-test-utils/src/database/sqlite.ts new file mode 100644 index 0000000000..92dc249225 --- /dev/null +++ b/packages/backend-test-utils/src/database/sqlite.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import knexFactory, { Knex } from 'knex'; +import { Engine, TestDatabaseProperties } from './types'; + +export class SqliteEngine implements Engine { + static async create( + properties: TestDatabaseProperties, + ): Promise { + return new SqliteEngine(properties); + } + + readonly #properties: TestDatabaseProperties; + readonly #instances: Knex[]; + + constructor(properties: TestDatabaseProperties) { + this.#properties = properties; + this.#instances = []; + } + + async createDatabaseInstance(): Promise { + const instance = knexFactory({ + client: this.#properties.driver, + connection: ':memory:', + useNullAsDefault: true, + }); + + instance.client.pool.on('createSuccess', (_eventId: any, resource: any) => { + resource.run('PRAGMA foreign_keys = ON', () => {}); + }); + + this.#instances.push(instance); + return instance; + } + + async shutdown(): Promise { + for (const instance of this.#instances) { + await instance.destroy(); + } + } +} diff --git a/packages/backend-test-utils/src/database/startMysqlContainer.ts b/packages/backend-test-utils/src/database/startMysqlContainer.ts deleted file mode 100644 index 2b4c917393..0000000000 --- a/packages/backend-test-utils/src/database/startMysqlContainer.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import createConnection, { Knex } from 'knex'; -import { v4 as uuid } from 'uuid'; - -async function waitForMysqlReady( - connection: Knex.MySqlConnectionConfig, -): Promise { - const startTime = Date.now(); - const db = createConnection({ client: 'mysql2', connection }); - - try { - for (;;) { - try { - const result = await db.select(db.raw('version() AS version')); - if (result[0]?.version) { - return; - } - } catch (e) { - if (Date.now() - startTime > 30_000) { - throw new Error( - `Timed out waiting for the database to be ready for connections, ${e}`, - ); - } - } - - await new Promise(resolve => setTimeout(resolve, 100)); - } - } finally { - db.destroy(); - } -} - -export async function startMysqlContainer(image: string) { - const user = 'root'; - const password = uuid(); - - // Lazy-load to avoid side-effect of importing testcontainers - const { GenericContainer } = await import('testcontainers'); - - const container = await new GenericContainer(image) - .withExposedPorts(3306) - .withEnvironment({ MYSQL_ROOT_PASSWORD: password }) - .withTmpFs({ '/var/lib/mysql': 'rw' }) - .start(); - - const host = container.getHost(); - const port = container.getMappedPort(3306); - const stop = async () => { - await container.stop({ timeout: 10_000 }); - }; - - await waitForMysqlReady({ host, port, user, password }); - - return { host, port, user, password, stop }; -} diff --git a/packages/backend-test-utils/src/database/startPostgresContainer.ts b/packages/backend-test-utils/src/database/startPostgresContainer.ts deleted file mode 100644 index 7a1c3f89c5..0000000000 --- a/packages/backend-test-utils/src/database/startPostgresContainer.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import createConnection, { Knex } from 'knex'; -import { v4 as uuid } from 'uuid'; - -async function waitForPostgresReady( - connection: Knex.PgConnectionConfig, -): Promise { - const startTime = Date.now(); - const db = createConnection({ client: 'pg', connection }); - - try { - for (;;) { - try { - const result = await db.select(db.raw('version()')); - if (Array.isArray(result) && result[0]?.version) { - return; - } - } catch (e) { - if (Date.now() - startTime > 30_000) { - throw new Error( - `Timed out waiting for the database to be ready for connections, ${e}`, - ); - } - } - - await new Promise(resolve => setTimeout(resolve, 100)); - } - } finally { - db.destroy(); - } -} - -export async function startPostgresContainer(image: string) { - const user = 'postgres'; - const password = uuid(); - - // Lazy-load to avoid side-effect of importing testcontainers - const { GenericContainer } = await import('testcontainers'); - - const container = await new GenericContainer(image) - .withExposedPorts(5432) - .withEnvironment({ POSTGRES_PASSWORD: password }) - .withTmpFs({ '/var/lib/postgresql/data': 'rw' }) - .start(); - - const host = container.getHost(); - const port = container.getMappedPort(5432); - const stop = async () => { - await container.stop({ timeout: 10_000 }); - }; - - await waitForPostgresReady({ host, port, user, password }); - - return { host, port, user, password, stop }; -} diff --git a/packages/backend-test-utils/src/database/types.ts b/packages/backend-test-utils/src/database/types.ts index 77a0c4e960..39a8af065c 100644 --- a/packages/backend-test-utils/src/database/types.ts +++ b/packages/backend-test-utils/src/database/types.ts @@ -14,10 +14,14 @@ * limitations under the License. */ -import { DatabaseManager } from '@backstage/backend-common'; import { Knex } from 'knex'; import { getDockerImageForName } from '../util/getDockerImageForName'; +export interface Engine { + createDatabaseInstance(): Promise; + shutdown(): Promise; +} + /** * The possible databases to test against. * @@ -41,14 +45,6 @@ export type TestDatabaseProperties = { connectionStringEnvironmentVariableName?: string; }; -export type Instance = { - stopContainer?: () => Promise; - dropDatabases?: () => Promise; - databaseManager: DatabaseManager; - connections: Array; - databaseNames: Array; -}; - export const allDatabases: Record = Object.freeze({ POSTGRES_16: { @@ -112,3 +108,10 @@ export const allDatabases: Record = driver: 'better-sqlite3', }, }); + +export const LARGER_POOL_CONFIG = { + pool: { + min: 0, + max: 50, + }, +}; diff --git a/packages/backend-test-utils/src/filesystem/MockDirectory.ts b/packages/backend-test-utils/src/filesystem/MockDirectory.ts index fff8a35a06..1c10c77fc6 100644 --- a/packages/backend-test-utils/src/filesystem/MockDirectory.ts +++ b/packages/backend-test-utils/src/filesystem/MockDirectory.ts @@ -15,7 +15,7 @@ */ import os from 'os'; -import { isChildPath } from '@backstage/backend-common'; +import { isChildPath } from '@backstage/backend-plugin-api'; import fs from 'fs-extra'; import textextensions from 'textextensions'; import { diff --git a/packages/backend-test-utils/src/index.ts b/packages/backend-test-utils/src/index.ts index ff1f2ee460..72abd908c5 100644 --- a/packages/backend-test-utils/src/index.ts +++ b/packages/backend-test-utils/src/index.ts @@ -20,6 +20,7 @@ * @packageDocumentation */ +export * from './cache'; export * from './database'; export * from './msw'; export * from './filesystem'; diff --git a/packages/backend-test-utils/src/next/services/mockCredentials.test.ts b/packages/backend-test-utils/src/next/services/mockCredentials.test.ts index ed0071d4b8..343d6d6d20 100644 --- a/packages/backend-test-utils/src/next/services/mockCredentials.test.ts +++ b/packages/backend-test-utils/src/next/services/mockCredentials.test.ts @@ -134,6 +134,16 @@ describe('mockCredentials', () => { expect(mockCredentials.service.invalidHeader()).toBe( 'Bearer mock-invalid-service-token', ); + expect( + mockCredentials.service('test', { permissionNames: ['do.it'] }), + ).toEqual({ + $$type: '@backstage/BackstageCredentials', + principal: { + type: 'service', + subject: 'test', + accessRestrictions: { permissionNames: ['do.it'] }, + }, + }); }); it('should throw on invalid user entity refs', () => { diff --git a/packages/backend-test-utils/src/next/services/mockCredentials.ts b/packages/backend-test-utils/src/next/services/mockCredentials.ts index 16d2381c73..4214320142 100644 --- a/packages/backend-test-utils/src/next/services/mockCredentials.ts +++ b/packages/backend-test-utils/src/next/services/mockCredentials.ts @@ -17,6 +17,7 @@ import { BackstageCredentials, BackstageNonePrincipal, + BackstagePrincipalAccessRestrictions, BackstageServicePrincipal, BackstageUserPrincipal, } from '@backstage/backend-plugin-api'; @@ -202,14 +203,19 @@ export namespace mockCredentials { /** * Creates a mocked credentials object for a service principal. * - * The default subject is 'external:test-service'. + * The default subject is 'external:test-service', and no access restrictions. */ export function service( subject: string = DEFAULT_MOCK_SERVICE_SUBJECT, + accessRestrictions?: BackstagePrincipalAccessRestrictions, ): BackstageCredentials { return { $$type: '@backstage/BackstageCredentials', - principal: { type: 'service', subject }, + principal: { + type: 'service', + subject, + ...(accessRestrictions ? { accessRestrictions } : {}), + }, }; } diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index a858bf7dbf..57621a9209 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -52,6 +52,21 @@ import { MockAuthService } from './MockAuthService'; import { MockHttpAuthService } from './MockHttpAuthService'; import { mockCredentials } from './mockCredentials'; import { MockUserInfoService } from './MockUserInfoService'; +import { + eventsServiceFactory, + eventsServiceRef, +} from '@backstage/plugin-events-node'; + +/** @internal */ +function createLoggerMock() { + return { + child: jest.fn().mockImplementation(createLoggerMock), + debug: jest.fn(), + error: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + }; +} /** @internal */ function simpleFactory< @@ -354,13 +369,10 @@ export namespace mockServices { export namespace logger { export const factory = loggerServiceFactory; - export const mock = simpleMock(coreServices.logger, () => ({ - child: jest.fn(), - debug: jest.fn(), - error: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - })); + + export const mock = simpleMock(coreServices.logger, () => + createLoggerMock(), + ); } export namespace permissions { @@ -397,4 +409,12 @@ export namespace mockServices { search: jest.fn(), })); } + + export namespace events { + export const factory = eventsServiceFactory; + export const mock = simpleMock(eventsServiceRef, () => ({ + publish: jest.fn(), + subscribe: jest.fn(), + })); + } } diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 10041dce4f..e43353991f 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -83,6 +83,7 @@ export const defaultServiceFactories = [ mockServices.tokenManager.factory(), mockServices.userInfo.factory(), mockServices.urlReader.factory(), + mockServices.events.factory(), ]; /** diff --git a/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts b/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts index b411086728..05eeabd91a 100644 --- a/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts +++ b/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts @@ -20,7 +20,7 @@ export function isDockerDisabledForTests() { // the (relatively heavy, long running) docker based tests. If you want to // still run local tests for all databases, just pass either the CI=1 env // parameter to your test runner, or individual connection strings per - // database. + // database or cache. return ( Boolean(process.env.BACKSTAGE_TEST_DISABLE_DOCKER) || !Boolean(process.env.CI) diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index ce08ade977..a8937ec456 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,82 +1,214 @@ # example-backend -## 0.2.98-next.0 +## 0.0.27-next.1 ### Patch Changes - Updated dependencies + - @backstage/backend-tasks@0.5.24-next.1 + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/plugin-permission-node@0.7.30-next.1 + - @backstage/plugin-search-backend@1.5.10-next.1 + - @backstage/backend-defaults@0.3.0-next.1 + - @backstage/plugin-kubernetes-backend@0.18.0-next.1 + - @backstage/plugin-catalog-backend@1.23.0-next.1 + - @backstage/plugin-scaffolder-backend@1.22.8-next.1 + - @backstage/plugin-notifications-backend@0.3.0-next.1 + - @backstage/plugin-app-backend@0.3.68-next.1 + - @backstage/plugin-auth-backend@0.22.6-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.5-next.1 + - @backstage/plugin-auth-node@0.4.14-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.37-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.1 + - @backstage/plugin-devtools-backend@0.3.5-next.1 + - @backstage/plugin-permission-backend@0.5.43-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.16-next.0 + - @backstage/plugin-proxy-backend@0.5.0-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.1 + - @backstage/plugin-search-backend-node@1.2.24-next.1 + - @backstage/plugin-signals-backend@0.1.5-next.1 + - @backstage/plugin-techdocs-backend@1.10.6-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.1 + +## 0.0.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.24-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.9-next.0 + - @backstage/plugin-devtools-backend@0.3.5-next.0 + - @backstage/plugin-techdocs-backend@1.10.6-next.0 + - @backstage/plugin-catalog-backend@1.23.0-next.0 + - @backstage/plugin-search-backend@1.5.10-next.0 + - @backstage/plugin-proxy-backend@0.5.0-next.0 + - @backstage/plugin-auth-backend@0.22.6-next.0 + - @backstage/plugin-app-backend@0.3.68-next.0 + - @backstage/plugin-search-backend-node@1.2.24-next.0 + - @backstage/plugin-signals-backend@0.1.5-next.0 + - @backstage/backend-defaults@0.2.19-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/plugin-scaffolder-backend@1.22.8-next.0 + - @backstage/plugin-kubernetes-backend@0.17.2-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.2-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.25-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.25-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.24-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.5-next.0 + - @backstage/plugin-auth-node@0.4.14-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.37-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.6-next.0 + - @backstage/plugin-notifications-backend@0.2.2-next.0 + - @backstage/plugin-permission-backend@0.5.43-next.0 + - @backstage/plugin-permission-node@0.7.30-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.16-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.17-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.16-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-permission-common@0.7.13 + +## 0.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.22.6 + - @backstage/plugin-catalog-backend@1.22.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.8 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5 + - @backstage/plugin-search-backend-module-catalog@0.1.24 + - @backstage/plugin-notifications-backend@0.2.1 + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + - @backstage/backend-tasks@0.5.23 + - @backstage/plugin-auth-backend@0.22.5 + - @backstage/plugin-app-backend@0.3.66 + - @backstage/plugin-devtools-backend@0.3.4 + - @backstage/plugin-signals-backend@0.1.4 + - @backstage/plugin-search-backend-node@1.2.22 + - @backstage/plugin-search-backend@1.5.8 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15 + - @backstage/plugin-techdocs-backend@1.10.5 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.4 + - @backstage/backend-defaults@0.2.18 + - @backstage/plugin-search-backend-module-explore@0.1.24 + - @backstage/plugin-auth-node@0.4.13 + - @backstage/plugin-search-backend-module-techdocs@0.1.23 + - @backstage/plugin-catalog-backend-module-openapi@0.1.36 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16 + - @backstage/plugin-kubernetes-backend@0.17.1 + - @backstage/plugin-permission-backend@0.5.42 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15 + - @backstage/plugin-permission-node@0.7.29 + - @backstage/plugin-proxy-backend@0.4.16 + +## 0.0.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.1 + - @backstage/plugin-notifications-backend@0.2.1-next.1 + - @backstage/plugin-catalog-backend@1.22.0-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.1 + - @backstage/plugin-scaffolder-backend@1.22.5-next.1 + - @backstage/plugin-search-backend@1.5.8-next.1 + - @backstage/backend-defaults@0.2.18-next.1 + - @backstage/plugin-app-backend@0.3.66-next.1 + - @backstage/plugin-kubernetes-backend@0.17.1-next.1 + - @backstage/backend-tasks@0.5.23-next.1 + - @backstage/plugin-auth-backend@0.22.5-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.4-next.1 + - @backstage/plugin-auth-node@0.4.13-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.36-next.1 + - @backstage/plugin-devtools-backend@0.3.4-next.1 + - @backstage/plugin-permission-backend@0.5.42-next.1 + - @backstage/plugin-permission-node@0.7.29-next.1 + - @backstage/plugin-proxy-backend@0.4.16-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.24-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.24-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.1 + - @backstage/plugin-search-backend-node@1.2.22-next.1 + - @backstage/plugin-signals-backend@0.1.4-next.1 + - @backstage/plugin-techdocs-backend@1.10.5-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.18-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1-next.1 + +## 0.0.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.2.8-next.0 - @backstage/plugin-catalog-backend@1.22.0-next.0 - @backstage/plugin-scaffolder-backend@1.22.5-next.0 - @backstage/catalog-model@1.5.0-next.0 - @backstage/plugin-search-backend-node@1.2.22-next.0 - @backstage/plugin-search-backend@1.5.8-next.0 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.4-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.23-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.1-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.4-next.0 - @backstage/plugin-search-backend-module-explore@0.1.23-next.0 - @backstage/plugin-auth-backend@0.22.5-next.0 - @backstage/plugin-auth-node@0.4.13-next.0 - - @backstage/backend-common@0.21.8-next.0 - - example-app@0.2.97-next.0 + - @backstage/plugin-notifications-backend@0.2.1-next.0 + - @backstage/backend-plugin-api@0.6.18-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.36-next.0 + - @backstage/backend-defaults@0.2.18-next.0 - @backstage/plugin-app-backend@0.3.66-next.0 - @backstage/plugin-kubernetes-backend@0.17.1-next.0 - - @backstage/catalog-client@1.6.5-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.16-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.5-next.0 - - @backstage/plugin-catalog-node@1.11.2-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.23-next.0 - @backstage/plugin-techdocs-backend@1.10.5-next.0 - @backstage/backend-tasks@0.5.23-next.0 - - @backstage/config@1.2.0 - - @backstage/integration@1.10.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.15-next.0 - @backstage/plugin-devtools-backend@0.3.4-next.0 - - @backstage/plugin-events-backend@0.3.5-next.0 - - @backstage/plugin-events-node@0.3.4-next.0 - @backstage/plugin-permission-backend@0.5.42-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.15-next.0 - @backstage/plugin-permission-common@0.7.13 - @backstage/plugin-permission-node@0.7.29-next.0 - @backstage/plugin-proxy-backend@0.4.16-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.19-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.35-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.4.1-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.27-next.0 - @backstage/plugin-signals-backend@0.1.4-next.0 - - @backstage/plugin-signals-node@0.1.4-next.0 -## 0.2.97 +## 0.0.25 ### Patch Changes - Updated dependencies - - @backstage/plugin-search-backend-module-pg@0.5.26 - @backstage/plugin-badges-backend@0.4.0 - @backstage/plugin-kubernetes-backend@0.17.0 - - @backstage/backend-common@0.21.7 - @backstage/plugin-azure-devops-backend@0.6.4 - @backstage/plugin-techdocs-backend@1.10.4 + - @backstage/plugin-notifications-backend@0.2.0 - @backstage/plugin-permission-node@0.7.28 - @backstage/plugin-auth-backend@0.22.4 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.3 - @backstage/plugin-catalog-backend@1.21.1 - - @backstage/plugin-events-backend@0.3.4 - - @backstage/plugin-tech-insights-node@0.6.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.0 + - @backstage/backend-plugin-api@0.6.17 - @backstage/plugin-search-backend@1.5.7 - @backstage/plugin-todo-backend@0.3.16 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.49 + - @backstage/plugin-scaffolder-backend-module-github@0.2.7 - @backstage/plugin-search-backend-module-techdocs@0.1.22 - @backstage/plugin-search-backend-module-explore@0.1.21 - @backstage/plugin-entity-feedback-backend@0.2.14 - - @backstage/plugin-code-coverage-backend@0.2.31 - - @backstage/plugin-tech-insights-backend@0.5.31 - @backstage/plugin-search-backend-node@1.2.21 - @backstage/plugin-lighthouse-backend@0.4.10 - @backstage/plugin-permission-backend@0.5.41 + - @backstage/plugin-sonarqube-backend@0.2.19 - @backstage/plugin-devtools-backend@0.3.3 - @backstage/plugin-linguist-backend@0.5.15 - @backstage/plugin-playlist-backend@0.3.21 - - @backstage/plugin-explore-backend@0.0.27 - @backstage/plugin-jenkins-backend@0.4.4 - @backstage/backend-tasks@0.5.22 - - @backstage/plugin-kafka-backend@0.3.15 - @backstage/plugin-nomad-backend@0.1.19 - @backstage/plugin-adr-backend@0.4.14 - @backstage/plugin-app-backend@0.3.65 @@ -84,218 +216,174 @@ - @backstage/plugin-signals-backend@0.1.3 - @backstage/plugin-proxy-backend@0.4.15 - @backstage/plugin-scaffolder-backend@1.22.4 - - @backstage/catalog-client@1.6.4 - - @backstage/integration@1.10.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.4.0 - - example-app@0.2.96 + - @backstage/backend-defaults@0.2.17 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.3 + - @backstage/plugin-catalog-backend-module-openapi@0.1.35 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4 - - @backstage/plugin-events-node@0.3.3 - - @backstage/plugin-rollbar-backend@0.1.62 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.18 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.34 - @backstage/plugin-search-backend-module-catalog@0.1.22 - - @backstage/plugin-signals-node@0.1.3 - - @backstage/plugin-catalog-node@1.11.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.14 - @backstage/catalog-model@1.4.5 - - @backstage/config@1.2.0 - - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.14 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15 - @backstage/plugin-permission-common@0.7.13 -## 0.2.97-next.1 +## 0.0.25-next.1 ### Patch Changes - Updated dependencies - @backstage/plugin-kubernetes-backend@0.17.0-next.1 - - @backstage/backend-common@0.21.7-next.1 - @backstage/plugin-azure-devops-backend@0.6.4-next.1 - @backstage/plugin-techdocs-backend@1.10.4-next.1 - - @backstage/plugin-events-backend@0.3.4-next.1 - @backstage/plugin-auth-backend@0.22.4-next.1 + - @backstage/backend-plugin-api@0.6.17-next.1 - @backstage/plugin-auth-node@0.4.12-next.1 - @backstage/plugin-proxy-backend@0.4.15-next.1 - @backstage/plugin-scaffolder-backend@1.22.4-next.1 - @backstage/plugin-catalog-backend@1.21.1-next.1 - - @backstage/catalog-client@1.6.4-next.0 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.3-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.2.7-next.1 - @backstage/plugin-app-backend@0.3.65-next.1 + - @backstage/plugin-notifications-backend@0.2.0-next.1 + - @backstage/backend-defaults@0.2.17-next.1 - @backstage/backend-tasks@0.5.22-next.1 - @backstage/plugin-adr-backend@0.4.14-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.3-next.1 - @backstage/plugin-badges-backend@0.3.14-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.35-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4-next.1 - - @backstage/plugin-code-coverage-backend@0.2.31-next.1 - @backstage/plugin-devtools-backend@0.3.3-next.1 - @backstage/plugin-entity-feedback-backend@0.2.14-next.1 - - @backstage/plugin-events-node@0.3.3-next.1 - - @backstage/plugin-explore-backend@0.0.27-next.1 - @backstage/plugin-jenkins-backend@0.4.4-next.1 - - @backstage/plugin-kafka-backend@0.3.15-next.1 - @backstage/plugin-lighthouse-backend@0.4.10-next.1 - @backstage/plugin-linguist-backend@0.5.15-next.1 - @backstage/plugin-nomad-backend@0.1.19-next.1 - @backstage/plugin-permission-backend@0.5.41-next.1 - @backstage/plugin-permission-node@0.7.28-next.1 - @backstage/plugin-playlist-backend@0.3.21-next.1 - - @backstage/plugin-rollbar-backend@0.1.62-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.18-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.34-next.1 - @backstage/plugin-search-backend@1.5.7-next.1 - @backstage/plugin-search-backend-module-catalog@0.1.22-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.20-next.1 - @backstage/plugin-search-backend-module-explore@0.1.21-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.26-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.22-next.1 - @backstage/plugin-search-backend-node@1.2.21-next.1 - @backstage/plugin-signals-backend@0.1.3-next.1 - - @backstage/plugin-signals-node@0.1.3-next.1 - - @backstage/plugin-tech-insights-backend@0.5.31-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.49-next.1 - - @backstage/plugin-tech-insights-node@0.5.3-next.1 + - @backstage/plugin-sonarqube-backend@0.2.19-next.1 - @backstage/plugin-todo-backend@0.3.16-next.1 - - example-app@0.2.96-next.1 - @backstage/catalog-model@1.4.5 - - @backstage/config@1.2.0 - - @backstage/integration@1.10.0-next.0 - - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.14-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.11-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15-next.1 - - @backstage/plugin-catalog-node@1.11.1-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.14-next.1 - @backstage/plugin-permission-common@0.7.13 -## 0.2.97-next.0 +## 0.0.25-next.0 ### Patch Changes - Updated dependencies - @backstage/plugin-techdocs-backend@1.10.4-next.0 - @backstage/plugin-catalog-backend@1.21.1-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.11-next.0 - @backstage/plugin-kubernetes-backend@0.16.4-next.0 - @backstage/plugin-signals-backend@0.1.3-next.0 - - @backstage/backend-common@0.21.7-next.0 - - @backstage/integration@1.10.0-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.22-next.0 - @backstage/plugin-scaffolder-backend@1.22.4-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.35-next.0 + - @backstage/backend-defaults@0.2.17-next.0 - @backstage/plugin-app-backend@0.3.65-next.0 - - example-app@0.2.96-next.0 + - @backstage/backend-plugin-api@0.6.17-next.0 - @backstage/backend-tasks@0.5.22-next.0 - - @backstage/catalog-client@1.6.3 - @backstage/catalog-model@1.4.5 - - @backstage/config@1.2.0 - @backstage/plugin-adr-backend@0.4.14-next.0 - @backstage/plugin-auth-backend@0.22.4-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.14-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.3-next.0 - @backstage/plugin-auth-node@0.4.12-next.0 - @backstage/plugin-azure-devops-backend@0.6.4-next.0 - - @backstage/plugin-azure-sites-common@0.1.3 - @backstage/plugin-badges-backend@0.3.14-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.15-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.4-next.0 - - @backstage/plugin-catalog-node@1.11.1-next.0 - - @backstage/plugin-code-coverage-backend@0.2.31-next.0 - @backstage/plugin-devtools-backend@0.3.3-next.0 - @backstage/plugin-entity-feedback-backend@0.2.14-next.0 - - @backstage/plugin-events-backend@0.3.3-next.0 - - @backstage/plugin-events-node@0.3.3-next.0 - - @backstage/plugin-explore-backend@0.0.27-next.0 - @backstage/plugin-jenkins-backend@0.4.4-next.0 - - @backstage/plugin-kafka-backend@0.3.15-next.0 - @backstage/plugin-lighthouse-backend@0.4.10-next.0 - @backstage/plugin-linguist-backend@0.5.15-next.0 - @backstage/plugin-nomad-backend@0.1.19-next.0 + - @backstage/plugin-notifications-backend@0.1.3-next.0 - @backstage/plugin-permission-backend@0.5.41-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.14-next.0 - @backstage/plugin-permission-common@0.7.13 - @backstage/plugin-permission-node@0.7.28-next.0 - @backstage/plugin-playlist-backend@0.3.21-next.0 - @backstage/plugin-proxy-backend@0.4.15-next.0 - - @backstage/plugin-rollbar-backend@0.1.62-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.18-next.0 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.3-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.34-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.7-next.0 - @backstage/plugin-search-backend@1.5.7-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.22-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.20-next.0 - @backstage/plugin-search-backend-module-explore@0.1.21-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.26-next.0 - @backstage/plugin-search-backend-node@1.2.21-next.0 - - @backstage/plugin-signals-node@0.1.3-next.0 - - @backstage/plugin-tech-insights-backend@0.5.31-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.49-next.0 - - @backstage/plugin-tech-insights-node@0.5.3-next.0 + - @backstage/plugin-sonarqube-backend@0.2.19-next.0 - @backstage/plugin-todo-backend@0.3.16-next.0 -## 0.2.96 +## 0.0.24 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.21.0 - - @backstage/plugin-catalog-node@1.11.0 - @backstage/plugin-kubernetes-backend@0.16.3 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.3 - @backstage/plugin-permission-backend@0.5.40 - @backstage/plugin-proxy-backend@0.4.14 - @backstage/plugin-scaffolder-backend@1.22.3 - - @backstage/catalog-client@1.6.3 - @backstage/plugin-jenkins-backend@0.4.3 - @backstage/plugin-auth-backend@0.22.3 - @backstage/plugin-auth-node@0.4.11 - - @backstage/backend-common@0.21.6 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.34 - @backstage/plugin-azure-devops-backend@0.6.3 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.10 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.14 - @backstage/plugin-lighthouse-backend@0.4.9 - @backstage/plugin-linguist-backend@0.5.14 - @backstage/plugin-search-backend-module-catalog@0.1.21 - @backstage/plugin-search-backend-module-techdocs@0.1.21 - @backstage/plugin-todo-backend@0.3.15 - - example-app@0.2.95 + - @backstage/backend-defaults@0.2.16 - @backstage/plugin-app-backend@0.3.64 - @backstage/plugin-adr-backend@0.4.13 - @backstage/plugin-badges-backend@0.3.13 - - @backstage/plugin-code-coverage-backend@0.2.30 - @backstage/plugin-entity-feedback-backend@0.2.13 + - @backstage/plugin-notifications-backend@0.1.2 - @backstage/plugin-playlist-backend@0.3.20 - - @backstage/plugin-tech-insights-backend@0.5.30 - @backstage/plugin-techdocs-backend@1.10.3 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.2 + - @backstage/plugin-auth-backend-module-github-provider@0.1.13 + - @backstage/backend-plugin-api@0.6.16 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.13 - @backstage/plugin-permission-node@0.7.27 - @backstage/plugin-signals-backend@0.1.2 - - @backstage/plugin-signals-node@0.1.2 - @backstage/backend-tasks@0.5.21 - @backstage/plugin-devtools-backend@0.3.2 - - @backstage/plugin-events-backend@0.3.2 - - @backstage/plugin-events-node@0.3.2 - - @backstage/plugin-explore-backend@0.0.26 - - @backstage/plugin-kafka-backend@0.3.14 - @backstage/plugin-nomad-backend@0.1.18 - - @backstage/plugin-rollbar-backend@0.1.61 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.17 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.33 + - @backstage/plugin-scaffolder-backend-module-github@0.2.6 - @backstage/plugin-search-backend@1.5.6 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.19 - @backstage/plugin-search-backend-module-explore@0.1.20 - - @backstage/plugin-search-backend-module-pg@0.5.25 - @backstage/plugin-search-backend-node@1.2.20 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.48 - - @backstage/plugin-tech-insights-node@0.5.2 + - @backstage/plugin-sonarqube-backend@0.2.18 - @backstage/catalog-model@1.4.5 - - @backstage/config@1.2.0 - - @backstage/integration@1.9.1 - - @backstage/plugin-azure-sites-common@0.1.3 - @backstage/plugin-permission-common@0.7.13 -## 0.2.95 +## 0.0.23 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.20.0 - - @backstage/plugin-catalog-node@1.10.0 - @backstage/plugin-kubernetes-backend@0.16.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.2 - @backstage/plugin-permission-backend@0.5.39 - - @backstage/catalog-client@1.6.2 - - @backstage/backend-common@0.21.5 + - @backstage/plugin-catalog-backend-module-openapi@0.1.33 - @backstage/plugin-auth-backend@0.22.2 - @backstage/plugin-azure-devops-backend@0.6.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.9 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.13 - @backstage/plugin-jenkins-backend@0.4.2 - @backstage/plugin-lighthouse-backend@0.4.8 @@ -304,55 +392,45 @@ - @backstage/plugin-search-backend-module-catalog@0.1.20 - @backstage/plugin-search-backend-module-techdocs@0.1.20 - @backstage/plugin-todo-backend@0.3.14 - - example-app@0.2.94 + - @backstage/backend-defaults@0.2.15 - @backstage/plugin-app-backend@0.3.63 - @backstage/plugin-adr-backend@0.4.12 - @backstage/plugin-auth-node@0.4.10 - @backstage/plugin-badges-backend@0.3.12 - - @backstage/plugin-code-coverage-backend@0.2.29 - @backstage/plugin-entity-feedback-backend@0.2.12 + - @backstage/plugin-notifications-backend@0.1.1 - @backstage/plugin-playlist-backend@0.3.19 - - @backstage/plugin-tech-insights-backend@0.5.29 - @backstage/plugin-techdocs-backend@1.10.2 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.1 - @backstage/backend-tasks@0.5.20 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.1 - @backstage/plugin-devtools-backend@0.3.1 - - @backstage/plugin-events-backend@0.3.1 - - @backstage/plugin-events-node@0.3.1 - - @backstage/plugin-explore-backend@0.0.25 - - @backstage/plugin-kafka-backend@0.3.13 - @backstage/plugin-nomad-backend@0.1.17 - @backstage/plugin-permission-node@0.7.26 - @backstage/plugin-proxy-backend@0.4.13 - - @backstage/plugin-rollbar-backend@0.1.60 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.16 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.32 + - @backstage/plugin-scaffolder-backend-module-github@0.2.5 - @backstage/plugin-search-backend@1.5.5 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.18 - @backstage/plugin-search-backend-module-explore@0.1.19 - - @backstage/plugin-search-backend-module-pg@0.5.24 - @backstage/plugin-search-backend-node@1.2.19 - @backstage/plugin-signals-backend@0.1.1 - - @backstage/plugin-signals-node@0.1.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.47 - - @backstage/plugin-tech-insights-node@0.5.1 + - @backstage/plugin-sonarqube-backend@0.2.17 + - @backstage/backend-plugin-api@0.6.15 - @backstage/catalog-model@1.4.5 - - @backstage/config@1.2.0 - - @backstage/integration@1.9.1 - - @backstage/plugin-azure-sites-common@0.1.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.12 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.12 - @backstage/plugin-permission-common@0.7.13 -## 0.2.94 +## 0.0.22 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.19.0 - - @backstage/plugin-catalog-node@1.9.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.1 - @backstage/plugin-permission-backend@0.5.38 + - @backstage/plugin-catalog-backend-module-openapi@0.1.32 - @backstage/plugin-auth-backend@0.22.1 - @backstage/plugin-azure-devops-backend@0.6.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.8 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.12 - @backstage/plugin-jenkins-backend@0.4.1 - @backstage/plugin-kubernetes-backend@0.16.1 @@ -362,157 +440,130 @@ - @backstage/plugin-search-backend-module-catalog@0.1.19 - @backstage/plugin-search-backend-module-techdocs@0.1.19 - @backstage/plugin-todo-backend@0.3.13 + - @backstage/plugin-auth-backend-module-github-provider@0.1.11 - @backstage/plugin-techdocs-backend@1.10.1 -## 0.2.93 +## 0.0.21 ### Patch Changes - Updated dependencies - - @backstage/plugin-events-backend@0.3.0 - - @backstage/plugin-events-node@0.3.0 + - @backstage/plugin-notifications-backend@0.1.0 - @backstage/plugin-scaffolder-backend@1.22.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.31 - @backstage/plugin-linguist-backend@0.5.11 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.7 - @backstage/plugin-catalog-backend-module-unprocessed@0.4.0 - @backstage/plugin-catalog-backend@1.18.0 - - @backstage/plugin-code-coverage-backend@0.2.28 - @backstage/plugin-devtools-backend@0.3.0 - @backstage/plugin-jenkins-backend@0.4.0 - @backstage/plugin-search-backend@1.5.4 - - @backstage/backend-common@0.21.4 - - @backstage/integration@1.9.1 - @backstage/plugin-auth-node@0.4.9 - @backstage/plugin-lighthouse-backend@0.4.6 - - @backstage/config@1.2.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.0 - @backstage/plugin-azure-devops-backend@0.6.0 - @backstage/plugin-permission-backend@0.5.37 - @backstage/plugin-signals-backend@0.1.0 - @backstage/plugin-nomad-backend@0.1.16 - @backstage/plugin-entity-feedback-backend@0.2.11 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.17 - - @backstage/plugin-search-backend-module-pg@0.5.23 - - @backstage/plugin-signals-node@0.1.0 - @backstage/plugin-playlist-backend@0.3.18 + - @backstage/backend-plugin-api@0.6.14 - @backstage/plugin-auth-backend@0.22.0 - @backstage/plugin-techdocs-backend@1.10.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.15 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.4 - @backstage/plugin-permission-common@0.7.13 - @backstage/plugin-search-backend-module-techdocs@0.1.18 - @backstage/plugin-search-backend-module-catalog@0.1.18 - @backstage/plugin-search-backend-module-explore@0.1.18 - - @backstage/plugin-catalog-node@1.8.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.46 - - @backstage/catalog-client@1.6.1 + - @backstage/backend-defaults@0.2.14 - @backstage/plugin-kubernetes-backend@0.16.0 - @backstage/plugin-adr-backend@0.4.11 - @backstage/plugin-proxy-backend@0.4.12 - @backstage/backend-tasks@0.5.19 - @backstage/plugin-search-backend-node@1.2.18 - - @backstage/plugin-tech-insights-backend@0.5.28 - @backstage/plugin-app-backend@0.3.62 - @backstage/plugin-permission-node@0.7.25 - @backstage/plugin-todo-backend@0.3.12 - - @backstage/plugin-tech-insights-node@0.5.0 - @backstage/plugin-badges-backend@0.3.11 - - example-app@0.2.93 + - @backstage/plugin-auth-backend-module-github-provider@0.1.11 + - @backstage/plugin-catalog-backend-module-openapi@0.1.31 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11 - - @backstage/plugin-explore-backend@0.0.24 - - @backstage/plugin-rollbar-backend@0.1.59 - - @backstage/plugin-kafka-backend@0.3.12 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.11 + - @backstage/plugin-sonarqube-backend@0.2.16 - @backstage/catalog-model@1.4.5 - - @backstage/plugin-azure-sites-common@0.1.3 -## 0.2.93-next.2 +## 0.0.21-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.22.0-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.31-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.7-next.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.11-next.2 - @backstage/plugin-catalog-backend@1.18.0-next.2 - - @backstage/plugin-code-coverage-backend@0.2.28-next.2 - @backstage/plugin-devtools-backend@0.3.0-next.2 - @backstage/plugin-jenkins-backend@0.4.0-next.2 - @backstage/plugin-search-backend@1.5.4-next.2 - - @backstage/integration@1.9.1-next.2 - @backstage/plugin-techdocs-backend@1.10.0-next.2 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.3.0-next.2 - - @backstage/plugin-signals-node@0.1.0-next.2 - - @backstage/catalog-client@1.6.1-next.1 + - @backstage/plugin-notifications-backend@0.1.0-next.2 - @backstage/plugin-linguist-backend@0.5.11-next.2 - @backstage/plugin-kubernetes-backend@0.16.0-next.2 - @backstage/plugin-todo-backend@0.3.12-next.2 - @backstage/plugin-signals-backend@0.1.0-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.15-next.2 - - @backstage/backend-common@0.21.4-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.2.4-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.31-next.2 - @backstage/plugin-adr-backend@0.4.11-next.2 - @backstage/plugin-azure-devops-backend@0.6.0-next.2 - - example-app@0.2.93-next.2 - @backstage/plugin-search-backend-module-techdocs@0.1.18-next.2 - @backstage/plugin-auth-backend@0.22.0-next.2 + - @backstage/backend-defaults@0.2.14-next.2 - @backstage/plugin-app-backend@0.3.62-next.2 - @backstage/plugin-auth-node@0.4.9-next.2 - @backstage/plugin-badges-backend@0.3.11-next.2 - - @backstage/plugin-catalog-node@1.8.0-next.2 - @backstage/plugin-entity-feedback-backend@0.2.11-next.2 - @backstage/plugin-lighthouse-backend@0.4.6-next.2 - @backstage/plugin-playlist-backend@0.3.18-next.2 - @backstage/plugin-search-backend-module-catalog@0.1.18-next.2 - - @backstage/plugin-tech-insights-backend@0.5.28-next.2 + - @backstage/backend-plugin-api@0.6.14-next.2 - @backstage/backend-tasks@0.5.19-next.2 - @backstage/catalog-model@1.4.5-next.0 - - @backstage/config@1.2.0-next.1 - - @backstage/plugin-azure-sites-common@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.11-next.2 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.0-next.2 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11-next.2 - - @backstage/plugin-events-backend@0.3.0-next.2 - - @backstage/plugin-events-node@0.3.0-next.2 - - @backstage/plugin-explore-backend@0.0.24-next.2 - - @backstage/plugin-kafka-backend@0.3.12-next.2 - @backstage/plugin-nomad-backend@0.1.16-next.2 - @backstage/plugin-permission-backend@0.5.37-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.11-next.2 - @backstage/plugin-permission-common@0.7.13-next.1 - @backstage/plugin-permission-node@0.7.25-next.2 - @backstage/plugin-proxy-backend@0.4.12-next.2 - - @backstage/plugin-rollbar-backend@0.1.59-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.17-next.2 - @backstage/plugin-search-backend-module-explore@0.1.18-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.23-next.2 - @backstage/plugin-search-backend-node@1.2.18-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.46-next.2 - - @backstage/plugin-tech-insights-node@0.5.0-next.2 + - @backstage/plugin-sonarqube-backend@0.2.16-next.2 -## 0.2.93-next.1 +## 0.0.21-next.1 ### Patch Changes - Updated dependencies - - @backstage/config@1.2.0-next.1 - @backstage/plugin-entity-feedback-backend@0.2.11-next.1 + - @backstage/plugin-notifications-backend@0.1.0-next.1 - @backstage/plugin-scaffolder-backend@1.22.0-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.17-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.0-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.2.4-next.1 - @backstage/plugin-app-backend@0.3.62-next.1 - @backstage/plugin-signals-backend@0.1.0-next.1 - - @backstage/plugin-signals-node@0.1.0-next.1 - @backstage/plugin-azure-devops-backend@0.6.0-next.1 - @backstage/plugin-kubernetes-backend@0.16.0-next.1 - - example-app@0.2.93-next.1 - - @backstage/backend-common@0.21.4-next.1 + - @backstage/backend-plugin-api@0.6.14-next.1 - @backstage/backend-tasks@0.5.19-next.1 - - @backstage/integration@1.9.1-next.1 - @backstage/plugin-adr-backend@0.4.11-next.1 - @backstage/plugin-auth-backend@0.22.0-next.1 - @backstage/plugin-auth-node@0.4.9-next.1 - @backstage/plugin-badges-backend@0.3.11-next.1 - @backstage/plugin-catalog-backend@1.18.0-next.1 - - @backstage/plugin-code-coverage-backend@0.2.28-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.7-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.31-next.1 - @backstage/plugin-devtools-backend@0.3.0-next.1 - - @backstage/plugin-events-backend@0.3.0-next.1 - - @backstage/plugin-explore-backend@0.0.24-next.1 - @backstage/plugin-jenkins-backend@0.4.0-next.1 - - @backstage/plugin-kafka-backend@0.3.12-next.1 - @backstage/plugin-lighthouse-backend@0.4.6-next.1 - @backstage/plugin-linguist-backend@0.5.11-next.1 - @backstage/plugin-nomad-backend@0.1.16-next.1 @@ -521,103 +572,78 @@ - @backstage/plugin-permission-node@0.7.25-next.1 - @backstage/plugin-playlist-backend@0.3.18-next.1 - @backstage/plugin-proxy-backend@0.4.12-next.1 - - @backstage/plugin-rollbar-backend@0.1.59-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.15-next.1 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.17-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.31-next.1 - @backstage/plugin-search-backend@1.5.4-next.1 - @backstage/plugin-search-backend-module-catalog@0.1.18-next.1 - @backstage/plugin-search-backend-module-explore@0.1.18-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.23-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.18-next.1 - @backstage/plugin-search-backend-node@1.2.18-next.1 - - @backstage/plugin-tech-insights-backend@0.5.28-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.46-next.1 - - @backstage/plugin-tech-insights-node@0.5.0-next.1 + - @backstage/plugin-sonarqube-backend@0.2.16-next.1 - @backstage/plugin-techdocs-backend@1.9.7-next.1 - @backstage/plugin-todo-backend@0.3.12-next.1 - - @backstage/catalog-client@1.6.1-next.0 + - @backstage/backend-defaults@0.2.14-next.1 - @backstage/catalog-model@1.4.5-next.0 - - @backstage/plugin-azure-sites-common@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.11-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.11-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.11-next.1 - - @backstage/plugin-catalog-node@1.8.0-next.1 - - @backstage/plugin-events-node@0.3.0-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.11-next.1 -## 0.2.93-next.0 +## 0.0.21-next.0 ### Patch Changes - Updated dependencies - - @backstage/plugin-events-backend@0.3.0-next.0 - - @backstage/plugin-events-node@0.3.0-next.0 - @backstage/plugin-linguist-backend@0.5.10-next.0 - - @backstage/backend-common@0.21.3-next.0 - @backstage/plugin-auth-node@0.4.8-next.0 - @backstage/plugin-lighthouse-backend@0.4.5-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.16-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.22-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.0-next.0 - @backstage/plugin-playlist-backend@0.3.17-next.0 - - @backstage/plugin-code-coverage-backend@0.2.27-next.0 + - @backstage/backend-plugin-api@0.6.13-next.0 - @backstage/plugin-entity-feedback-backend@0.2.10-next.0 + - @backstage/plugin-notifications-backend@0.1.0-next.0 - @backstage/plugin-catalog-backend@1.18.0-next.0 - @backstage/plugin-auth-backend@0.22.0-next.0 - @backstage/plugin-jenkins-backend@0.4.0-next.0 - @backstage/plugin-azure-devops-backend@0.6.0-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.14-next.0 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.16-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.30-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.2.3-next.0 - @backstage/plugin-scaffolder-backend@1.22.0-next.0 - @backstage/plugin-permission-common@0.7.13-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.17-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.17-next.0 - @backstage/plugin-search-backend-module-explore@0.1.17-next.0 - - @backstage/plugin-catalog-node@1.8.0-next.0 + - @backstage/backend-defaults@0.2.13-next.0 - @backstage/plugin-kubernetes-backend@0.16.0-next.0 - @backstage/plugin-adr-backend@0.4.10-next.0 - @backstage/plugin-proxy-backend@0.4.11-next.0 - @backstage/backend-tasks@0.5.18-next.0 - @backstage/plugin-search-backend-node@1.2.17-next.0 - @backstage/plugin-signals-backend@0.0.4-next.0 - - @backstage/plugin-signals-node@0.0.4-next.0 - - @backstage/plugin-tech-insights-backend@0.5.27-next.0 - @backstage/plugin-search-backend@1.5.3-next.0 - @backstage/plugin-devtools-backend@0.3.0-next.0 - @backstage/plugin-permission-node@0.7.24-next.0 - - @backstage/plugin-tech-insights-node@0.5.0-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.6-next.0 - @backstage/plugin-badges-backend@0.3.10-next.0 - @backstage/plugin-permission-backend@0.5.36-next.0 - @backstage/plugin-app-backend@0.3.61-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.10-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.30-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.10-next.0 - - @backstage/plugin-explore-backend@0.0.23-next.0 - - @backstage/plugin-rollbar-backend@0.1.58-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.45-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.10-next.0 + - @backstage/plugin-sonarqube-backend@0.2.15-next.0 - @backstage/plugin-techdocs-backend@1.9.6-next.0 - - @backstage/plugin-kafka-backend@0.3.11-next.0 - @backstage/plugin-nomad-backend@0.1.15-next.0 - @backstage/plugin-todo-backend@0.3.11-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.10-next.0 - - example-app@0.2.93-next.0 - - @backstage/catalog-client@1.6.1-next.0 - @backstage/catalog-model@1.4.5-next.0 - - @backstage/config@1.1.2-next.0 - - @backstage/integration@1.9.1-next.0 - - @backstage/plugin-azure-sites-common@0.1.3-next.0 -## 0.2.92 +## 0.0.20 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.21.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.27 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7 - @backstage/plugin-scaffolder-backend@1.21.0 - @backstage/plugin-badges-backend@0.3.7 - @backstage/plugin-azure-devops-backend@0.5.2 - - @backstage/plugin-explore-backend@0.0.20 - - @backstage/plugin-auth-backend@0.21.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42 - @backstage/plugin-auth-node@0.4.4 - @backstage/plugin-entity-feedback-backend@0.2.7 - @backstage/plugin-lighthouse-backend@0.4.2 @@ -625,75 +651,56 @@ - @backstage/plugin-linguist-backend@0.5.7 - @backstage/plugin-adr-backend@0.4.7 - @backstage/plugin-kubernetes-backend@0.15.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.13 - @backstage/plugin-signals-backend@0.0.1 - - @backstage/plugin-signals-node@0.0.1 - - @backstage/plugin-tech-insights-backend@0.5.24 - - @backstage/plugin-tech-insights-node@0.4.16 + - @backstage/plugin-notifications-backend@0.0.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.27 - @backstage/plugin-search-backend-module-techdocs@0.1.14 - @backstage/plugin-search-backend-module-catalog@0.1.14 - @backstage/plugin-search-backend-module-explore@0.1.14 - - @backstage/plugin-code-coverage-backend@0.2.24 + - @backstage/backend-plugin-api@0.6.10 + - @backstage/backend-defaults@0.2.10 + - @backstage/plugin-sonarqube-backend@0.2.12 - @backstage/plugin-playlist-backend@0.3.14 - @backstage/plugin-catalog-backend@1.17.0 - @backstage/plugin-jenkins-backend@0.3.4 - - @backstage/plugin-rollbar-backend@0.1.55 - @backstage/backend-tasks@0.5.15 - - @backstage/plugin-events-backend@0.2.19 - @backstage/plugin-nomad-backend@0.1.12 - @backstage/plugin-app-backend@0.3.58 - - @backstage/catalog-model@1.4.4 - - @backstage/integration@1.9.0 - - @backstage/catalog-client@1.6.0 - @backstage/plugin-search-backend@1.5.0 - @backstage/plugin-todo-backend@0.3.8 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3 - @backstage/plugin-techdocs-backend@1.9.3 - - @backstage/plugin-catalog-node@1.7.0 - - @backstage/plugin-azure-sites-common@0.1.2 - - example-app@0.2.92 - - @backstage/plugin-kafka-backend@0.3.8 - @backstage/plugin-permission-backend@0.5.33 - @backstage/plugin-permission-node@0.7.21 - @backstage/plugin-proxy-backend@0.4.8 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.13 - - @backstage/plugin-search-backend-module-pg@0.5.19 - @backstage/plugin-search-backend-node@1.2.14 - - @backstage/config@1.1.1 - - @backstage/plugin-events-node@0.2.19 - @backstage/plugin-permission-common@0.7.12 - - @backstage/plugin-search-common@1.2.10 -## 0.2.92-next.3 +## 0.0.20-next.3 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.21.0-next.3 - @backstage/plugin-badges-backend@0.3.7-next.3 - @backstage/plugin-kubernetes-backend@0.15.0-next.3 - - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.13-next.3 - - @backstage/integration@1.9.0-next.1 - @backstage/backend-tasks@0.5.15-next.3 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.3 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.3 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.3 + - @backstage/plugin-notifications-backend@0.0.1-next.1 - @backstage/plugin-signals-backend@0.0.1-next.3 - - @backstage/plugin-signals-node@0.0.1-next.3 - @backstage/plugin-catalog-backend@1.17.0-next.3 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.3 - @backstage/plugin-app-backend@0.3.58-next.3 - - @backstage/plugin-auth-backend@0.21.0-next.3 - - @backstage/plugin-catalog-node@1.6.2-next.3 + - @backstage/backend-defaults@0.2.10-next.3 - @backstage/plugin-adr-backend@0.4.7-next.3 - @backstage/plugin-auth-node@0.4.4-next.3 - @backstage/plugin-azure-devops-backend@0.5.2-next.3 - - @backstage/plugin-code-coverage-backend@0.2.24-next.3 + - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.3 - @backstage/plugin-devtools-backend@0.2.7-next.3 - @backstage/plugin-entity-feedback-backend@0.2.7-next.3 - - @backstage/plugin-events-backend@0.2.19-next.3 - - @backstage/plugin-explore-backend@0.0.20-next.3 - @backstage/plugin-jenkins-backend@0.3.4-next.3 - - @backstage/plugin-kafka-backend@0.3.8-next.3 - @backstage/plugin-lighthouse-backend@0.4.2-next.3 - @backstage/plugin-linguist-backend@0.5.7-next.3 - @backstage/plugin-nomad-backend@0.1.12-next.3 @@ -701,243 +708,170 @@ - @backstage/plugin-permission-node@0.7.21-next.3 - @backstage/plugin-playlist-backend@0.3.14-next.3 - @backstage/plugin-proxy-backend@0.4.8-next.3 - - @backstage/plugin-rollbar-backend@0.1.55-next.3 - @backstage/plugin-scaffolder-backend@1.21.0-next.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.3 - @backstage/plugin-search-backend@1.5.0-next.3 - @backstage/plugin-search-backend-module-catalog@0.1.14-next.3 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.3 - @backstage/plugin-search-backend-module-explore@0.1.14-next.3 - - @backstage/plugin-search-backend-module-pg@0.5.19-next.3 - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.3 - @backstage/plugin-search-backend-node@1.2.14-next.3 - - @backstage/plugin-tech-insights-backend@0.5.24-next.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.3 - - @backstage/plugin-tech-insights-node@0.4.16-next.3 + - @backstage/plugin-sonarqube-backend@0.2.12-next.3 - @backstage/plugin-techdocs-backend@1.9.3-next.3 - @backstage/plugin-todo-backend@0.3.8-next.3 - - example-app@0.2.92-next.3 - - @backstage/catalog-client@1.6.0-next.1 - - @backstage/catalog-model@1.4.4-next.0 - - @backstage/config@1.1.1 - - @backstage/plugin-azure-sites-common@0.1.2-next.0 + - @backstage/backend-plugin-api@0.6.10-next.3 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.3 - - @backstage/plugin-events-node@0.2.19-next.3 - @backstage/plugin-permission-common@0.7.12 - - @backstage/plugin-search-common@1.2.10 -## 0.2.92-next.2 +## 0.0.20-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.21.0-next.2 - - @backstage/plugin-auth-backend@0.21.0-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.2 - - @backstage/backend-common@0.21.0-next.2 - @backstage/plugin-signals-backend@0.0.1-next.2 - - @backstage/plugin-signals-node@0.0.1-next.2 - @backstage/plugin-kubernetes-backend@0.15.0-next.2 - - @backstage/plugin-tech-insights-backend@0.5.24-next.2 - - @backstage/plugin-tech-insights-node@0.4.16-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.2 - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.2 - @backstage/plugin-search-backend-module-catalog@0.1.14-next.2 - @backstage/plugin-search-backend-module-explore@0.1.14-next.2 - @backstage/plugin-entity-feedback-backend@0.2.7-next.2 - - @backstage/plugin-code-coverage-backend@0.2.24-next.2 - @backstage/plugin-azure-devops-backend@0.5.2-next.2 + - @backstage/backend-plugin-api@0.6.10-next.2 - @backstage/plugin-lighthouse-backend@0.4.2-next.2 + - @backstage/backend-defaults@0.2.10-next.2 + - @backstage/plugin-sonarqube-backend@0.2.12-next.2 - @backstage/plugin-devtools-backend@0.2.7-next.2 - @backstage/plugin-linguist-backend@0.5.7-next.2 - @backstage/plugin-playlist-backend@0.3.14-next.2 - @backstage/plugin-catalog-backend@1.17.0-next.2 - - @backstage/plugin-explore-backend@0.0.20-next.2 - @backstage/plugin-jenkins-backend@0.3.4-next.2 - - @backstage/plugin-rollbar-backend@0.1.55-next.2 - @backstage/backend-tasks@0.5.15-next.2 - @backstage/plugin-badges-backend@0.3.7-next.2 - - @backstage/plugin-events-backend@0.2.19-next.2 - @backstage/plugin-nomad-backend@0.1.12-next.2 - @backstage/plugin-adr-backend@0.4.7-next.2 - @backstage/plugin-app-backend@0.3.58-next.2 - @backstage/plugin-auth-node@0.4.4-next.2 - - example-app@0.2.92-next.2 + - @backstage/plugin-notifications-backend@0.0.1-next.0 - @backstage/plugin-todo-backend@0.3.8-next.2 - - @backstage/plugin-kafka-backend@0.3.8-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.2 - @backstage/plugin-permission-backend@0.5.33-next.2 - @backstage/plugin-permission-node@0.7.21-next.2 - @backstage/plugin-proxy-backend@0.4.8-next.2 - @backstage/plugin-search-backend@1.5.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.19-next.2 - @backstage/plugin-search-backend-node@1.2.14-next.2 - @backstage/plugin-techdocs-backend@1.9.3-next.2 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.2 - - @backstage/plugin-catalog-node@1.6.2-next.2 - - @backstage/plugin-events-node@0.2.19-next.2 - - @backstage/config@1.1.1 - - @backstage/catalog-client@1.6.0-next.1 - - @backstage/catalog-model@1.4.4-next.0 - - @backstage/integration@1.9.0-next.0 - - @backstage/plugin-azure-sites-common@0.1.2-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.2 - @backstage/plugin-permission-common@0.7.12 - - @backstage/plugin-search-common@1.2.10 -## 0.2.92-next.1 +## 0.0.20-next.1 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.21.0-next.1 - @backstage/plugin-azure-devops-backend@0.5.2-next.1 - - @backstage/catalog-model@1.4.4-next.0 - - @backstage/catalog-client@1.6.0-next.1 - @backstage/plugin-catalog-backend@1.17.0-next.1 - - @backstage/backend-common@0.21.0-next.1 - - @backstage/plugin-auth-backend@0.20.4-next.1 - - @backstage/integration@1.9.0-next.0 - - @backstage/plugin-azure-sites-common@0.1.2-next.0 - - example-app@0.2.92-next.1 + - @backstage/backend-plugin-api@0.6.10-next.1 + - @backstage/backend-defaults@0.2.10-next.1 - @backstage/backend-tasks@0.5.15-next.1 - - @backstage/config@1.1.1 - @backstage/plugin-adr-backend@0.4.7-next.1 - @backstage/plugin-app-backend@0.3.58-next.1 - @backstage/plugin-auth-node@0.4.4-next.1 - @backstage/plugin-badges-backend@0.3.7-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.1 - - @backstage/plugin-catalog-node@1.6.2-next.1 - - @backstage/plugin-code-coverage-backend@0.2.24-next.1 - @backstage/plugin-devtools-backend@0.2.7-next.1 - @backstage/plugin-entity-feedback-backend@0.2.7-next.1 - - @backstage/plugin-events-backend@0.2.19-next.1 - - @backstage/plugin-events-node@0.2.19-next.1 - - @backstage/plugin-explore-backend@0.0.20-next.1 - @backstage/plugin-jenkins-backend@0.3.4-next.1 - - @backstage/plugin-kafka-backend@0.3.8-next.1 - @backstage/plugin-kubernetes-backend@0.14.2-next.1 - @backstage/plugin-lighthouse-backend@0.4.2-next.1 - @backstage/plugin-linguist-backend@0.5.7-next.1 - @backstage/plugin-nomad-backend@0.1.12-next.1 - @backstage/plugin-permission-backend@0.5.33-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.1 - @backstage/plugin-permission-common@0.7.12 - @backstage/plugin-permission-node@0.7.21-next.1 - @backstage/plugin-playlist-backend@0.3.14-next.1 - @backstage/plugin-proxy-backend@0.4.8-next.1 - - @backstage/plugin-rollbar-backend@0.1.55-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.1 - @backstage/plugin-search-backend@1.5.0-next.1 - @backstage/plugin-search-backend-module-catalog@0.1.14-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.1 - @backstage/plugin-search-backend-module-explore@0.1.14-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.19-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.1 - @backstage/plugin-search-backend-node@1.2.14-next.1 - - @backstage/plugin-search-common@1.2.10 - - @backstage/plugin-signals-backend@0.0.1-next.1 - - @backstage/plugin-signals-node@0.0.1-next.1 - - @backstage/plugin-tech-insights-backend@0.5.24-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.1 - - @backstage/plugin-tech-insights-node@0.4.16-next.1 + - @backstage/plugin-sonarqube-backend@0.2.12-next.1 - @backstage/plugin-techdocs-backend@1.9.3-next.1 - @backstage/plugin-todo-backend@0.3.8-next.1 -## 0.2.92-next.0 +## 0.0.20-next.0 ### Patch Changes - Updated dependencies - - @backstage/plugin-scaffolder-backend-module-rails@0.4.27-next.0 - @backstage/plugin-azure-devops-backend@0.5.2-next.0 - - @backstage/plugin-explore-backend@0.0.20-next.0 - - @backstage/plugin-auth-backend@0.20.4-next.0 - - @backstage/backend-common@0.21.0-next.0 - @backstage/plugin-kubernetes-backend@0.14.2-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.11-next.0 - @backstage/plugin-catalog-backend@1.17.0-next.0 - @backstage/plugin-search-backend@1.5.0-next.0 - @backstage/plugin-todo-backend@0.3.8-next.0 - - @backstage/catalog-client@1.6.0-next.0 - - @backstage/plugin-signals-backend@0.0.1-next.0 - - @backstage/plugin-signals-node@0.0.1-next.0 - @backstage/plugin-scaffolder-backend@1.21.0-next.0 - @backstage/plugin-app-backend@0.3.58-next.0 - - example-app@0.2.92-next.0 + - @backstage/backend-defaults@0.2.10-next.0 - @backstage/backend-tasks@0.5.15-next.0 - @backstage/plugin-auth-node@0.4.4-next.0 - @backstage/plugin-badges-backend@0.3.7-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.27-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.7-next.0 - - @backstage/plugin-catalog-node@1.6.2-next.0 - @backstage/plugin-entity-feedback-backend@0.2.7-next.0 - - @backstage/plugin-events-backend@0.2.19-next.0 - @backstage/plugin-linguist-backend@0.5.7-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.7-next.0 - @backstage/plugin-permission-node@0.7.21-next.0 - @backstage/plugin-playlist-backend@0.3.14-next.0 - @backstage/plugin-proxy-backend@0.4.8-next.0 - - @backstage/plugin-rollbar-backend@0.1.55-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.14-next.0 - @backstage/plugin-search-backend-module-explore@0.1.14-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.19-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.14-next.0 - - @backstage/plugin-tech-insights-backend@0.5.24-next.0 + - @backstage/plugin-sonarqube-backend@0.2.12-next.0 - @backstage/plugin-techdocs-backend@1.9.3-next.0 - @backstage/plugin-adr-backend@0.4.7-next.0 - - @backstage/plugin-azure-sites-backend@0.1.20-next.0 - - @backstage/plugin-code-coverage-backend@0.2.24-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.3-next.0 - @backstage/plugin-devtools-backend@0.2.7-next.0 - @backstage/plugin-jenkins-backend@0.3.4-next.0 - - @backstage/plugin-kafka-backend@0.3.8-next.0 - @backstage/plugin-lighthouse-backend@0.4.2-next.0 - @backstage/plugin-nomad-backend@0.1.12-next.0 - @backstage/plugin-permission-backend@0.5.33-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.13-next.0 - @backstage/plugin-search-backend-node@1.2.14-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.42-next.0 - - @backstage/plugin-tech-insights-node@0.4.16-next.0 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.10-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.7-next.0 - - @backstage/plugin-events-node@0.2.19-next.0 - @backstage/plugin-permission-common@0.7.12 - - @backstage/plugin-search-common@1.2.10 -## 0.2.91 +## 0.0.19 ### Patch Changes - Updated dependencies - - @backstage/plugin-auth-backend@0.20.3 - - @backstage/backend-common@0.20.1 + - @backstage/plugin-sonarqube-backend@0.2.11 - @backstage/plugin-scaffolder-backend@1.20.0 - - @backstage/catalog-client@1.5.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10 - - @backstage/plugin-events-backend@0.2.18 + - @backstage/plugin-catalog-backend-module-openapi@0.1.26 - @backstage/plugin-search-backend-module-techdocs@0.1.13 - @backstage/plugin-search-backend-module-catalog@0.1.13 - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-defaults@0.2.9 - @backstage/plugin-azure-devops-backend@0.5.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2 - @backstage/plugin-entity-feedback-backend@0.2.6 - - @backstage/plugin-code-coverage-backend@0.2.23 - - @backstage/plugin-azure-sites-backend@0.1.19 - - @backstage/plugin-tech-insights-node@0.4.15 - @backstage/plugin-devtools-backend@0.2.6 - @backstage/plugin-linguist-backend@0.5.6 - @backstage/plugin-playlist-backend@0.3.13 - @backstage/plugin-techdocs-backend@1.9.2 - - @backstage/plugin-explore-backend@0.0.19 - @backstage/plugin-jenkins-backend@0.3.3 - @backstage/plugin-badges-backend@0.3.6 - @backstage/plugin-search-backend@1.4.9 - - @backstage/plugin-kafka-backend@0.3.7 - @backstage/plugin-nomad-backend@0.1.11 - - @backstage/plugin-catalog-node@1.6.1 - @backstage/plugin-todo-backend@0.3.7 - @backstage/plugin-adr-backend@0.4.6 - @backstage/plugin-app-backend@0.3.57 @@ -945,211 +879,149 @@ - @backstage/plugin-permission-common@0.7.12 - @backstage/plugin-permission-node@0.7.20 - @backstage/plugin-catalog-backend@1.16.1 - - example-app@0.2.91 - @backstage/backend-tasks@0.5.14 - @backstage/plugin-auth-node@0.4.3 - @backstage/plugin-kubernetes-backend@0.14.1 - @backstage/plugin-lighthouse-backend@0.4.1 - @backstage/plugin-proxy-backend@0.4.7 - - @backstage/plugin-rollbar-backend@0.1.54 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.26 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.12 - - @backstage/plugin-search-backend-module-pg@0.5.18 - @backstage/plugin-search-backend-node@1.2.13 - - @backstage/plugin-tech-insights-backend@0.5.23 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/integration@1.8.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 - - @backstage/plugin-events-node@0.2.18 - - @backstage/plugin-search-common@1.2.10 -## 0.2.91-next.2 +## 0.0.19-next.2 ### Patch Changes - Updated dependencies - - example-app@0.2.91-next.2 - - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-sonarqube-backend@0.2.11-next.2 + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-defaults@0.2.9-next.2 - @backstage/plugin-adr-backend@0.4.6-next.2 - @backstage/plugin-app-backend@0.3.57-next.2 - - @backstage/plugin-auth-backend@0.20.3-next.2 - @backstage/plugin-auth-node@0.4.3-next.2 - @backstage/plugin-azure-devops-backend@0.5.1-next.2 - @backstage/plugin-badges-backend@0.3.6-next.2 - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.2 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.2 - - @backstage/plugin-catalog-node@1.6.1-next.2 - - @backstage/plugin-code-coverage-backend@0.2.23-next.2 - @backstage/plugin-devtools-backend@0.2.6-next.2 - @backstage/plugin-entity-feedback-backend@0.2.6-next.2 - - @backstage/plugin-events-backend@0.2.18-next.2 - - @backstage/plugin-events-node@0.2.18-next.2 - @backstage/plugin-jenkins-backend@0.3.3-next.2 - - @backstage/plugin-kafka-backend@0.3.7-next.2 - @backstage/plugin-kubernetes-backend@0.14.1-next.2 - @backstage/plugin-lighthouse-backend@0.4.1-next.2 - @backstage/plugin-linguist-backend@0.5.6-next.2 - @backstage/plugin-nomad-backend@0.1.11-next.2 - @backstage/plugin-permission-backend@0.5.32-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.2 - @backstage/plugin-permission-node@0.7.20-next.2 - @backstage/plugin-playlist-backend@0.3.13-next.2 - @backstage/plugin-proxy-backend@0.4.7-next.2 - @backstage/plugin-scaffolder-backend@1.19.3-next.2 - @backstage/plugin-search-backend@1.4.9-next.2 - @backstage/plugin-search-backend-module-catalog@0.1.13-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.2 - @backstage/plugin-search-backend-module-explore@0.1.13-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.18-next.2 - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.2 - @backstage/plugin-search-backend-node@1.2.13-next.2 - @backstage/plugin-techdocs-backend@1.9.2-next.2 - @backstage/plugin-todo-backend@0.3.7-next.2 - @backstage/backend-tasks@0.5.14-next.2 - - @backstage/plugin-azure-sites-backend@0.1.19-next.2 - - @backstage/plugin-explore-backend@0.0.19-next.2 - - @backstage/plugin-rollbar-backend@0.1.54-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.2 - - @backstage/plugin-tech-insights-backend@0.5.23-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.2 - - @backstage/plugin-tech-insights-node@0.4.15-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.2 -## 0.2.91-next.1 +## 0.0.19-next.1 ### Patch Changes - Updated dependencies - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.1 - - example-app@0.2.91-next.1 - - @backstage/backend-common@0.20.1-next.1 - - @backstage/integration@1.8.0 - @backstage/plugin-app-backend@0.3.57-next.1 - @backstage/plugin-devtools-backend@0.2.6-next.1 - @backstage/plugin-proxy-backend@0.4.7-next.1 - - @backstage/config@1.1.1 + - @backstage/backend-defaults@0.2.9-next.1 - @backstage/plugin-kubernetes-backend@0.14.1-next.1 - @backstage/backend-tasks@0.5.14-next.1 - @backstage/plugin-adr-backend@0.4.6-next.1 - - @backstage/plugin-auth-backend@0.20.3-next.1 - @backstage/plugin-auth-node@0.4.3-next.1 - @backstage/plugin-azure-devops-backend@0.5.1-next.1 - - @backstage/plugin-azure-sites-backend@0.1.19-next.1 - @backstage/plugin-badges-backend@0.3.6-next.1 - @backstage/plugin-catalog-backend@1.16.1-next.1 - - @backstage/plugin-code-coverage-backend@0.2.23-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.1 - @backstage/plugin-entity-feedback-backend@0.2.6-next.1 - - @backstage/plugin-events-backend@0.2.18-next.1 - - @backstage/plugin-explore-backend@0.0.19-next.1 - @backstage/plugin-jenkins-backend@0.3.3-next.1 - - @backstage/plugin-kafka-backend@0.3.7-next.1 - @backstage/plugin-lighthouse-backend@0.4.1-next.1 - @backstage/plugin-linguist-backend@0.5.6-next.1 - @backstage/plugin-nomad-backend@0.1.11-next.1 - @backstage/plugin-permission-backend@0.5.32-next.1 - @backstage/plugin-permission-node@0.7.20-next.1 - @backstage/plugin-playlist-backend@0.3.13-next.1 - - @backstage/plugin-rollbar-backend@0.1.54-next.1 - @backstage/plugin-scaffolder-backend@1.19.3-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.1 - @backstage/plugin-search-backend@1.4.9-next.1 - @backstage/plugin-search-backend-module-catalog@0.1.13-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.1 - @backstage/plugin-search-backend-module-explore@0.1.13-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.18-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.1 - @backstage/plugin-search-backend-node@1.2.13-next.1 - - @backstage/plugin-tech-insights-backend@0.5.23-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.1 - - @backstage/plugin-tech-insights-node@0.4.15-next.1 + - @backstage/plugin-sonarqube-backend@0.2.11-next.1 - @backstage/plugin-techdocs-backend@1.9.2-next.1 - @backstage/plugin-todo-backend@0.3.7-next.1 - - @backstage/catalog-client@1.5.2-next.0 - - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.9-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.1 - - @backstage/plugin-catalog-node@1.6.1-next.1 - - @backstage/plugin-events-node@0.2.18-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.1 - @backstage/plugin-permission-common@0.7.11 - - @backstage/plugin-search-common@1.2.9 -## 0.2.91-next.0 +## 0.0.19-next.0 ### Patch Changes - Updated dependencies - - @backstage/plugin-auth-backend@0.20.3-next.0 - - @backstage/backend-common@0.20.1-next.0 - @backstage/plugin-scaffolder-backend@1.19.3-next.0 - - @backstage/catalog-client@1.5.2-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.13-next.0 - @backstage/plugin-search-backend-module-explore@0.1.13-next.0 - @backstage/plugin-azure-devops-backend@0.5.1-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.0 - @backstage/plugin-entity-feedback-backend@0.2.6-next.0 - - @backstage/plugin-code-coverage-backend@0.2.23-next.0 - - @backstage/plugin-azure-sites-backend@0.1.19-next.0 - - @backstage/plugin-tech-insights-node@0.4.15-next.0 - @backstage/plugin-devtools-backend@0.2.6-next.0 - @backstage/plugin-linguist-backend@0.5.6-next.0 - @backstage/plugin-playlist-backend@0.3.13-next.0 - @backstage/plugin-techdocs-backend@1.9.2-next.0 - - @backstage/plugin-explore-backend@0.0.19-next.0 - @backstage/plugin-jenkins-backend@0.3.3-next.0 - @backstage/plugin-badges-backend@0.3.6-next.0 - @backstage/plugin-search-backend@1.4.9-next.0 - - @backstage/plugin-kafka-backend@0.3.7-next.0 - @backstage/plugin-nomad-backend@0.1.11-next.0 - - @backstage/plugin-catalog-node@1.6.1-next.0 - @backstage/plugin-todo-backend@0.3.7-next.0 - @backstage/plugin-adr-backend@0.4.6-next.0 - @backstage/plugin-app-backend@0.3.57-next.0 - - example-app@0.2.91-next.0 + - @backstage/backend-defaults@0.2.9-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 - @backstage/backend-tasks@0.5.14-next.0 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/integration@1.8.0 - @backstage/plugin-auth-node@0.4.3-next.0 - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.0 - - @backstage/plugin-events-backend@0.2.18-next.0 - - @backstage/plugin-events-node@0.2.18-next.0 - @backstage/plugin-kubernetes-backend@0.14.1-next.0 - @backstage/plugin-lighthouse-backend@0.4.1-next.0 - @backstage/plugin-permission-backend@0.5.32-next.0 - @backstage/plugin-permission-common@0.7.11 - @backstage/plugin-permission-node@0.7.20-next.0 - @backstage/plugin-proxy-backend@0.4.7-next.0 - - @backstage/plugin-rollbar-backend@0.1.54-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.18-next.0 - @backstage/plugin-search-backend-node@1.2.13-next.0 - - @backstage/plugin-search-common@1.2.9 - - @backstage/plugin-tech-insights-backend@0.5.23-next.0 + - @backstage/plugin-sonarqube-backend@0.2.11-next.0 -## 0.2.90 +## 0.0.18 ### Patch Changes - Updated dependencies - - @backstage/plugin-auth-backend@0.20.1 - - @backstage/backend-common@0.20.0 - - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1 - @backstage/plugin-techdocs-backend@1.9.1 - @backstage/plugin-catalog-backend@1.16.0 - - @backstage/catalog-client@1.5.0 - @backstage/plugin-azure-devops-backend@0.5.0 - @backstage/plugin-scaffolder-backend@1.19.2 - @backstage/backend-tasks@0.5.13 - @backstage/plugin-lighthouse-backend@0.4.0 - @backstage/plugin-kubernetes-backend@0.14.0 - - @backstage/integration@1.8.0 - - @backstage/plugin-azure-sites-backend@0.1.18 - @backstage/plugin-auth-node@0.4.2 - @backstage/plugin-permission-backend@0.5.31 - @backstage/plugin-permission-common@0.7.11 @@ -1157,134 +1029,94 @@ - @backstage/plugin-permission-node@0.7.19 - @backstage/plugin-search-backend@1.4.8 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.11 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5 - @backstage/plugin-search-backend-module-techdocs@0.1.12 - @backstage/plugin-search-backend-module-catalog@0.1.12 - @backstage/plugin-search-backend-module-explore@0.1.12 - - @backstage/plugin-search-backend-module-pg@0.5.17 - - @backstage/plugin-events-backend@0.2.17 - - example-app@0.2.90 + - @backstage/backend-defaults@0.2.8 - @backstage/plugin-adr-backend@0.4.5 - @backstage/plugin-app-backend@0.3.56 - @backstage/plugin-badges-backend@0.3.5 - - @backstage/plugin-code-coverage-backend@0.2.22 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25 - @backstage/plugin-devtools-backend@0.2.5 - @backstage/plugin-entity-feedback-backend@0.2.5 - - @backstage/plugin-explore-backend@0.0.18 - @backstage/plugin-jenkins-backend@0.3.2 - - @backstage/plugin-kafka-backend@0.3.6 - @backstage/plugin-linguist-backend@0.5.5 - @backstage/plugin-nomad-backend@0.1.10 - @backstage/plugin-proxy-backend@0.4.6 - - @backstage/plugin-rollbar-backend@0.1.53 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.25 - @backstage/plugin-search-backend-node@1.2.12 - - @backstage/plugin-tech-insights-backend@0.5.22 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40 - - @backstage/plugin-tech-insights-node@0.4.14 + - @backstage/plugin-sonarqube-backend@0.2.10 - @backstage/plugin-todo-backend@0.3.6 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/plugin-events-node@0.2.17 - - @backstage/plugin-search-common@1.2.9 + - @backstage/backend-plugin-api@0.6.8 -## 0.2.90-next.3 +## 0.0.18-next.3 ### Patch Changes - Updated dependencies - @backstage/plugin-azure-devops-backend@0.5.0-next.3 - @backstage/plugin-scaffolder-backend@1.19.2-next.3 - - @backstage/backend-common@0.20.0-next.3 - - example-app@0.2.90-next.4 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.3 + - @backstage/backend-defaults@0.2.8-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 - @backstage/backend-tasks@0.5.13-next.3 - - @backstage/catalog-client@1.5.0-next.1 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/integration@1.8.0-next.1 - @backstage/plugin-adr-backend@0.4.5-next.3 - @backstage/plugin-app-backend@0.3.56-next.3 - - @backstage/plugin-auth-backend@0.20.1-next.3 - @backstage/plugin-auth-node@0.4.2-next.3 - - @backstage/plugin-azure-sites-backend@0.1.18-next.3 - @backstage/plugin-badges-backend@0.3.5-next.3 - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.3 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.3 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.3 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.3 - - @backstage/plugin-catalog-node@1.6.0-next.3 - - @backstage/plugin-code-coverage-backend@0.2.22-next.3 - @backstage/plugin-devtools-backend@0.2.5-next.3 - @backstage/plugin-entity-feedback-backend@0.2.5-next.3 - - @backstage/plugin-events-backend@0.2.17-next.3 - - @backstage/plugin-events-node@0.2.17-next.3 - - @backstage/plugin-explore-backend@0.0.18-next.3 - @backstage/plugin-jenkins-backend@0.3.2-next.3 - - @backstage/plugin-kafka-backend@0.3.6-next.3 - @backstage/plugin-kubernetes-backend@0.14.0-next.3 - @backstage/plugin-lighthouse-backend@0.4.0-next.3 - @backstage/plugin-linguist-backend@0.5.5-next.3 - @backstage/plugin-nomad-backend@0.1.10-next.3 - @backstage/plugin-permission-backend@0.5.31-next.3 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.3 - @backstage/plugin-permission-common@0.7.10 - @backstage/plugin-permission-node@0.7.19-next.3 - @backstage/plugin-playlist-backend@0.3.12-next.3 - @backstage/plugin-proxy-backend@0.4.6-next.3 - - @backstage/plugin-rollbar-backend@0.1.53-next.3 - @backstage/plugin-search-backend@1.4.8-next.3 - @backstage/plugin-search-backend-module-catalog@0.1.12-next.3 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.3 - @backstage/plugin-search-backend-module-explore@0.1.12-next.3 - - @backstage/plugin-search-backend-module-pg@0.5.17-next.3 - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.3 - @backstage/plugin-search-backend-node@1.2.12-next.3 - - @backstage/plugin-search-common@1.2.8 - - @backstage/plugin-tech-insights-backend@0.5.22-next.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.3 - - @backstage/plugin-tech-insights-node@0.4.14-next.3 + - @backstage/plugin-sonarqube-backend@0.2.10-next.3 - @backstage/plugin-techdocs-backend@1.9.1-next.3 - @backstage/plugin-todo-backend@0.3.6-next.3 -## 0.2.90-next.2 +## 0.0.18-next.2 ### Patch Changes - Updated dependencies - - @backstage/plugin-catalog-node@1.6.0-next.2 - @backstage/plugin-catalog-backend@1.16.0-next.2 - - @backstage/plugin-auth-backend@0.20.1-next.2 - @backstage/plugin-lighthouse-backend@0.4.0-next.2 - - @backstage/backend-common@0.20.0-next.2 - @backstage/plugin-auth-node@0.4.2-next.2 - - @backstage/catalog-client@1.5.0-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.2 - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.2 - @backstage/plugin-search-backend-module-catalog@0.1.12-next.2 - @backstage/plugin-search-backend-module-explore@0.1.12-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.17-next.2 - - @backstage/plugin-events-backend@0.2.17-next.2 - - example-app@0.2.90-next.3 + - @backstage/backend-defaults@0.2.8-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 - @backstage/backend-tasks@0.5.13-next.2 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/integration@1.8.0-next.1 - @backstage/plugin-adr-backend@0.4.5-next.2 - @backstage/plugin-app-backend@0.3.56-next.2 - @backstage/plugin-azure-devops-backend@0.5.0-next.2 - - @backstage/plugin-azure-sites-backend@0.1.18-next.2 - @backstage/plugin-badges-backend@0.3.5-next.2 - - @backstage/plugin-code-coverage-backend@0.2.22-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.2 - @backstage/plugin-devtools-backend@0.2.5-next.2 - @backstage/plugin-entity-feedback-backend@0.2.5-next.2 - - @backstage/plugin-events-node@0.2.17-next.2 - - @backstage/plugin-explore-backend@0.0.18-next.2 - @backstage/plugin-jenkins-backend@0.3.2-next.2 - - @backstage/plugin-kafka-backend@0.3.6-next.2 - @backstage/plugin-kubernetes-backend@0.14.0-next.2 - @backstage/plugin-linguist-backend@0.5.5-next.2 - @backstage/plugin-nomad-backend@0.1.10-next.2 @@ -1293,230 +1125,165 @@ - @backstage/plugin-permission-node@0.7.19-next.2 - @backstage/plugin-playlist-backend@0.3.12-next.2 - @backstage/plugin-proxy-backend@0.4.6-next.2 - - @backstage/plugin-rollbar-backend@0.1.53-next.2 - @backstage/plugin-scaffolder-backend@1.19.2-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.2 - @backstage/plugin-search-backend@1.4.8-next.2 - @backstage/plugin-search-backend-node@1.2.12-next.2 - - @backstage/plugin-search-common@1.2.8 - - @backstage/plugin-tech-insights-backend@0.5.22-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.2 - - @backstage/plugin-tech-insights-node@0.4.14-next.2 + - @backstage/plugin-sonarqube-backend@0.2.10-next.2 - @backstage/plugin-techdocs-backend@1.9.1-next.2 - @backstage/plugin-todo-backend@0.3.6-next.2 -## 0.2.90-next.1 +## 0.0.18-next.1 ### Patch Changes - Updated dependencies - - @backstage/plugin-auth-backend@0.20.1-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.1 - @backstage/plugin-catalog-backend@1.15.1-next.1 - - @backstage/catalog-client@1.5.0-next.0 - @backstage/plugin-azure-devops-backend@0.5.0-next.1 - @backstage/plugin-kubernetes-backend@0.14.0-next.1 - - @backstage/integration@1.8.0-next.1 - - @backstage/plugin-azure-sites-backend@0.1.18-next.1 - - @backstage/backend-common@0.20.0-next.1 - - example-app@0.2.90-next.2 + - @backstage/backend-defaults@0.2.8-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 - @backstage/backend-tasks@0.5.13-next.1 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - @backstage/plugin-adr-backend@0.4.5-next.1 - @backstage/plugin-app-backend@0.3.56-next.1 - @backstage/plugin-auth-node@0.4.2-next.1 - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 - - @backstage/plugin-catalog-node@1.5.1-next.1 - - @backstage/plugin-code-coverage-backend@0.2.22-next.1 - @backstage/plugin-devtools-backend@0.2.5-next.1 - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 - - @backstage/plugin-events-backend@0.2.17-next.1 - - @backstage/plugin-events-node@0.2.17-next.1 - - @backstage/plugin-explore-backend@0.0.18-next.1 - @backstage/plugin-jenkins-backend@0.3.2-next.1 - - @backstage/plugin-kafka-backend@0.3.6-next.1 - @backstage/plugin-lighthouse-backend@0.3.5-next.1 - @backstage/plugin-linguist-backend@0.5.5-next.1 - @backstage/plugin-nomad-backend@0.1.10-next.1 - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.1 - @backstage/plugin-permission-common@0.7.10 - @backstage/plugin-permission-node@0.7.19-next.1 - @backstage/plugin-playlist-backend@0.3.12-next.1 - @backstage/plugin-proxy-backend@0.4.6-next.1 - - @backstage/plugin-rollbar-backend@0.1.53-next.1 - @backstage/plugin-scaffolder-backend@1.19.2-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.1 - @backstage/plugin-search-backend@1.4.8-next.1 - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.1 - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.17-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 - @backstage/plugin-search-backend-node@1.2.12-next.1 - - @backstage/plugin-search-common@1.2.8 - - @backstage/plugin-tech-insights-backend@0.5.22-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.1 - - @backstage/plugin-tech-insights-node@0.4.14-next.1 + - @backstage/plugin-sonarqube-backend@0.2.10-next.1 - @backstage/plugin-techdocs-backend@1.9.1-next.1 - @backstage/plugin-todo-backend@0.3.6-next.1 -## 0.2.90-next.0 +## 0.0.18-next.0 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.20.0-next.0 - - @backstage/plugin-auth-backend@0.20.1-next.0 - @backstage/backend-tasks@0.5.13-next.0 - @backstage/plugin-scaffolder-backend@1.19.2-next.0 - @backstage/plugin-kubernetes-backend@0.14.0-next.0 - - @backstage/plugin-azure-sites-backend@0.1.18-next.0 - - @backstage/integration@1.8.0-next.0 - - example-app@0.2.90-next.0 + - @backstage/backend-defaults@0.2.8-next.0 - @backstage/plugin-adr-backend@0.4.5-next.0 - @backstage/plugin-app-backend@0.3.56-next.0 - @backstage/plugin-auth-node@0.4.2-next.0 - @backstage/plugin-azure-devops-backend@0.4.5-next.0 - @backstage/plugin-badges-backend@0.3.5-next.0 - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.0 - - @backstage/plugin-catalog-node@1.5.1-next.0 - - @backstage/plugin-code-coverage-backend@0.2.22-next.0 - @backstage/plugin-devtools-backend@0.2.5-next.0 - @backstage/plugin-entity-feedback-backend@0.2.5-next.0 - - @backstage/plugin-events-backend@0.2.17-next.0 - - @backstage/plugin-explore-backend@0.0.18-next.0 - @backstage/plugin-jenkins-backend@0.3.2-next.0 - - @backstage/plugin-kafka-backend@0.3.6-next.0 - @backstage/plugin-lighthouse-backend@0.3.5-next.0 - @backstage/plugin-linguist-backend@0.5.5-next.0 - @backstage/plugin-nomad-backend@0.1.10-next.0 - @backstage/plugin-permission-backend@0.5.31-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.0 - @backstage/plugin-permission-node@0.7.19-next.0 - @backstage/plugin-playlist-backend@0.3.12-next.0 - @backstage/plugin-proxy-backend@0.4.6-next.0 - - @backstage/plugin-rollbar-backend@0.1.53-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.0 - @backstage/plugin-search-backend@1.4.8-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.12-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.0 - @backstage/plugin-search-backend-module-explore@0.1.12-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.17-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.0 - @backstage/plugin-search-backend-node@1.2.12-next.0 - - @backstage/plugin-tech-insights-backend@0.5.22-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.0 - - @backstage/plugin-tech-insights-node@0.4.14-next.0 + - @backstage/plugin-sonarqube-backend@0.2.10-next.0 - @backstage/plugin-techdocs-backend@1.9.1-next.0 - @backstage/plugin-todo-backend@0.3.6-next.0 - - @backstage/catalog-client@1.4.6 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.8-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.0 - - @backstage/plugin-events-node@0.2.17-next.0 - @backstage/plugin-permission-common@0.7.10 - - @backstage/plugin-search-common@1.2.8 -## 0.2.89 +## 0.0.17 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.15.0 - - @backstage/plugin-catalog-node@1.5.0 - - @backstage/plugin-search-backend-module-pg@0.5.16 - @backstage/plugin-kubernetes-backend@0.13.1 - @backstage/plugin-search-backend-node@1.2.11 - - @backstage/integration@1.7.2 - - @backstage/plugin-auth-backend@0.20.0 - - @backstage/backend-common@0.19.9 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0 - @backstage/plugin-techdocs-backend@1.9.0 - - @backstage/plugin-code-coverage-backend@0.2.21 - @backstage/plugin-scaffolder-backend@1.19.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.10 - @backstage/plugin-search-backend@1.4.7 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4 - @backstage/plugin-entity-feedback-backend@0.2.4 - - @backstage/plugin-tech-insights-backend@0.5.21 + - @backstage/backend-plugin-api@0.6.7 - @backstage/plugin-linguist-backend@0.5.4 - @backstage/plugin-playlist-backend@0.3.11 - @backstage/backend-tasks@0.5.12 - @backstage/plugin-badges-backend@0.3.4 - @backstage/plugin-app-backend@0.3.55 - @backstage/plugin-search-backend-module-techdocs@0.1.11 - - @backstage/catalog-client@1.4.6 - @backstage/plugin-permission-common@0.7.10 - @backstage/plugin-jenkins-backend@0.3.1 - @backstage/plugin-adr-backend@0.4.4 - - @backstage/plugin-kafka-backend@0.3.5 - @backstage/plugin-proxy-backend@0.4.5 - - example-app@0.2.89 + - @backstage/plugin-catalog-backend-module-openapi@0.1.24 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4 - @backstage/plugin-lighthouse-backend@0.3.4 - @backstage/plugin-search-backend-module-catalog@0.1.11 - @backstage/plugin-todo-backend@0.3.5 - @backstage/plugin-devtools-backend@0.2.4 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 + - @backstage/backend-defaults@0.2.7 - @backstage/plugin-auth-node@0.4.1 - @backstage/plugin-azure-devops-backend@0.4.4 - - @backstage/plugin-azure-sites-backend@0.1.17 - - @backstage/plugin-events-backend@0.2.16 - - @backstage/plugin-events-node@0.2.16 - - @backstage/plugin-explore-backend@0.0.17 - - @backstage/plugin-graphql-backend@0.2.1 - @backstage/plugin-nomad-backend@0.1.9 - @backstage/plugin-permission-backend@0.5.30 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4 - @backstage/plugin-permission-node@0.7.18 - - @backstage/plugin-rollbar-backend@0.1.52 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.24 - @backstage/plugin-search-backend-module-explore@0.1.11 - - @backstage/plugin-search-common@1.2.8 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39 - - @backstage/plugin-tech-insights-node@0.4.13 + - @backstage/plugin-sonarqube-backend@0.2.9 -## 0.2.89-next.2 +## 0.0.17-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-kubernetes-backend@0.13.1-next.2 - @backstage/plugin-scaffolder-backend@1.19.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.10-next.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.16-next.2 - @backstage/plugin-entity-feedback-backend@0.2.4-next.2 - - @backstage/plugin-code-coverage-backend@0.2.21-next.2 - - @backstage/plugin-tech-insights-backend@0.5.21-next.2 + - @backstage/backend-plugin-api@0.6.7-next.2 - @backstage/plugin-linguist-backend@0.5.4-next.2 - @backstage/plugin-playlist-backend@0.3.11-next.2 - @backstage/plugin-techdocs-backend@1.9.0-next.2 - - @backstage/backend-common@0.19.9-next.2 - @backstage/plugin-catalog-backend@1.15.0-next.2 - @backstage/backend-tasks@0.5.12-next.2 - @backstage/plugin-badges-backend@0.3.4-next.2 - - @backstage/plugin-auth-backend@0.20.0-next.2 - @backstage/plugin-app-backend@0.3.55-next.2 - - example-app@0.2.89-next.2 + - @backstage/backend-defaults@0.2.7-next.2 - @backstage/plugin-adr-backend@0.4.4-next.2 - @backstage/plugin-auth-node@0.4.1-next.2 - @backstage/plugin-azure-devops-backend@0.4.4-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0-next.2 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.2 - - @backstage/plugin-catalog-node@1.5.0-next.2 - @backstage/plugin-devtools-backend@0.2.4-next.2 - - @backstage/plugin-events-backend@0.2.16-next.2 - - @backstage/plugin-events-node@0.2.16-next.2 - @backstage/plugin-jenkins-backend@0.3.1-next.2 - - @backstage/plugin-kafka-backend@0.3.5-next.2 - @backstage/plugin-lighthouse-backend@0.3.4-next.2 - @backstage/plugin-nomad-backend@0.1.9-next.2 - @backstage/plugin-permission-backend@0.5.30-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4-next.2 - @backstage/plugin-permission-node@0.7.18-next.2 - @backstage/plugin-proxy-backend@0.4.5-next.2 - @backstage/plugin-search-backend@1.4.7-next.2 @@ -1524,27 +1291,20 @@ - @backstage/plugin-search-backend-module-explore@0.1.11-next.2 - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.2 - @backstage/plugin-search-backend-node@1.2.11-next.2 + - @backstage/plugin-sonarqube-backend@0.2.9-next.2 - @backstage/plugin-todo-backend@0.3.5-next.2 - - @backstage/plugin-rollbar-backend@0.1.52-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.24-next.2 - - @backstage/plugin-azure-sites-backend@0.1.17-next.2 - - @backstage/plugin-explore-backend@0.0.17-next.2 - - @backstage/plugin-graphql-backend@0.2.1-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39-next.2 - - @backstage/plugin-tech-insights-node@0.4.13-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.1.24-next.2 -## 0.2.89-next.1 +## 0.0.17-next.1 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.15.0-next.1 - - @backstage/plugin-catalog-node@1.5.0-next.1 - - @backstage/integration@1.7.2-next.0 - - @backstage/plugin-auth-backend@0.20.0-next.1 - @backstage/plugin-techdocs-backend@1.9.0-next.1 - @backstage/plugin-scaffolder-backend@1.19.0-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.24-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.1 - @backstage/plugin-jenkins-backend@0.3.1-next.1 - @backstage/plugin-kubernetes-backend@0.13.1-next.1 @@ -1553,351 +1313,230 @@ - @backstage/plugin-search-backend-module-catalog@0.1.11-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.1 - @backstage/plugin-todo-backend@0.3.5-next.1 - - example-app@0.2.89-next.1 - - @backstage/backend-common@0.19.9-next.1 - @backstage/plugin-adr-backend@0.4.4-next.1 - - @backstage/plugin-code-coverage-backend@0.2.21-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.24-next.1 + - @backstage/backend-defaults@0.2.7-next.1 - @backstage/backend-tasks@0.5.12-next.1 - @backstage/plugin-app-backend@0.3.55-next.1 - @backstage/plugin-auth-node@0.4.1-next.1 - @backstage/plugin-badges-backend@0.3.4-next.1 - @backstage/plugin-entity-feedback-backend@0.2.4-next.1 - - @backstage/plugin-events-backend@0.2.16-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4-next.1 - @backstage/plugin-permission-node@0.7.18-next.1 - @backstage/plugin-playlist-backend@0.3.11-next.1 - @backstage/plugin-proxy-backend@0.4.5-next.1 - - @backstage/plugin-rollbar-backend@0.1.52-next.1 - @backstage/plugin-search-backend@1.4.7-next.1 - @backstage/plugin-search-backend-module-explore@0.1.11-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.16-next.1 - - @backstage/plugin-tech-insights-backend@0.5.21-next.1 + - @backstage/plugin-sonarqube-backend@0.2.9-next.1 - @backstage/plugin-azure-devops-backend@0.4.4-next.1 - - @backstage/plugin-azure-sites-backend@0.1.17-next.1 - @backstage/plugin-devtools-backend@0.2.4-next.1 - - @backstage/plugin-explore-backend@0.0.17-next.1 - - @backstage/plugin-graphql-backend@0.2.1-next.1 - - @backstage/plugin-kafka-backend@0.3.5-next.1 - @backstage/plugin-nomad-backend@0.1.9-next.1 - @backstage/plugin-permission-backend@0.5.30-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.10-next.1 - @backstage/plugin-search-backend-node@1.2.11-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39-next.1 - - @backstage/plugin-tech-insights-node@0.4.13-next.1 - - @backstage/catalog-client@1.4.5 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.7-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.1 - - @backstage/plugin-events-node@0.2.16-next.1 - @backstage/plugin-permission-common@0.7.9 - - @backstage/plugin-search-common@1.2.7 -## 0.2.89-next.0 +## 0.0.17-next.0 ### Patch Changes - Updated dependencies - @backstage/plugin-search-backend-node@1.2.11-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0-next.0 - @backstage/plugin-techdocs-backend@1.8.1-next.0 - - @backstage/plugin-code-coverage-backend@0.2.21-next.0 - @backstage/plugin-scaffolder-backend@1.19.0-next.0 - @backstage/plugin-catalog-backend@1.15.0-next.0 - @backstage/plugin-search-backend@1.4.7-next.0 - - @backstage/plugin-tech-insights-backend@0.5.21-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.11-next.0 - - @backstage/plugin-kafka-backend@0.3.5-next.0 - @backstage/plugin-proxy-backend@0.4.5-next.0 - - @backstage/plugin-auth-backend@0.20.0-next.0 - - @backstage/backend-common@0.19.9-next.0 - - @backstage/integration@1.7.1 - @backstage/plugin-app-backend@0.3.55-next.0 - @backstage/plugin-devtools-backend@0.2.4-next.0 - - example-app@0.2.89-next.0 + - @backstage/backend-defaults@0.2.7-next.0 + - @backstage/backend-plugin-api@0.6.7-next.0 - @backstage/backend-tasks@0.5.12-next.0 - - @backstage/catalog-client@1.4.5 - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - @backstage/plugin-adr-backend@0.4.4-next.0 - @backstage/plugin-auth-node@0.4.1-next.0 - @backstage/plugin-azure-devops-backend@0.4.4-next.0 - - @backstage/plugin-azure-sites-backend@0.1.17-next.0 - @backstage/plugin-badges-backend@0.3.4-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.24-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.4-next.0 - - @backstage/plugin-catalog-node@1.4.8-next.0 - @backstage/plugin-entity-feedback-backend@0.2.4-next.0 - - @backstage/plugin-events-backend@0.2.16-next.0 - - @backstage/plugin-events-node@0.2.16-next.0 - - @backstage/plugin-explore-backend@0.0.17-next.0 - - @backstage/plugin-graphql-backend@0.2.1-next.0 - @backstage/plugin-jenkins-backend@0.3.1-next.0 - @backstage/plugin-kubernetes-backend@0.13.1-next.0 - @backstage/plugin-lighthouse-backend@0.3.4-next.0 - @backstage/plugin-linguist-backend@0.5.4-next.0 - @backstage/plugin-nomad-backend@0.1.9-next.0 - @backstage/plugin-permission-backend@0.5.30-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4-next.0 - @backstage/plugin-permission-common@0.7.9 - @backstage/plugin-permission-node@0.7.18-next.0 - @backstage/plugin-playlist-backend@0.3.11-next.0 - - @backstage/plugin-rollbar-backend@0.1.52-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.24-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.11-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.10-next.0 - @backstage/plugin-search-backend-module-explore@0.1.11-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.16-next.0 - - @backstage/plugin-search-common@1.2.7 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39-next.0 - - @backstage/plugin-tech-insights-node@0.4.13-next.0 + - @backstage/plugin-sonarqube-backend@0.2.9-next.0 - @backstage/plugin-todo-backend@0.3.5-next.0 -## 0.2.88 +## 0.0.16 ### Patch Changes - Updated dependencies - @backstage/plugin-nomad-backend@0.1.8 - @backstage/backend-tasks@0.5.11 - - @backstage/backend-common@0.19.8 + - @backstage/plugin-sonarqube-backend@0.2.8 - @backstage/plugin-scaffolder-backend@1.18.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.9 - - @backstage/integration@1.7.1 - @backstage/plugin-playlist-backend@0.3.10 - @backstage/plugin-techdocs-backend@1.8.0 - - @backstage/plugin-auth-backend@0.19.3 - - @backstage/plugin-rollbar-backend@0.1.51 - @backstage/plugin-catalog-backend@1.14.0 - - @backstage/plugin-catalog-node@1.4.7 - @backstage/plugin-auth-node@0.4.0 - - @backstage/plugin-graphql-backend@0.2.0 - - @backstage/catalog-model@1.4.3 - @backstage/plugin-badges-backend@0.3.3 - - @backstage/plugin-tech-insights-backend@0.5.20 - @backstage/plugin-kubernetes-backend@0.13.0 - @backstage/plugin-jenkins-backend@0.3.0 - - @backstage/plugin-code-coverage-backend@0.2.20 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.23 - @backstage/plugin-search-backend@1.4.6 - - example-app@0.2.88 + - @backstage/backend-plugin-api@0.6.6 - @backstage/plugin-lighthouse-backend@0.3.3 - @backstage/plugin-linguist-backend@0.5.3 - @backstage/plugin-search-backend-module-catalog@0.1.10 - @backstage/plugin-search-backend-module-explore@0.1.10 - @backstage/plugin-search-backend-module-techdocs@0.1.10 - @backstage/plugin-search-backend-node@1.2.10 - - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/backend-defaults@0.2.6 - @backstage/plugin-adr-backend@0.4.3 - @backstage/plugin-app-backend@0.3.54 - @backstage/plugin-azure-devops-backend@0.4.3 - - @backstage/plugin-azure-sites-backend@0.1.16 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 - @backstage/plugin-devtools-backend@0.2.3 - @backstage/plugin-entity-feedback-backend@0.2.3 - - @backstage/plugin-events-backend@0.2.15 - - @backstage/plugin-explore-backend@0.0.16 - - @backstage/plugin-kafka-backend@0.3.3 - @backstage/plugin-permission-backend@0.5.29 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.3 - @backstage/plugin-permission-node@0.7.17 - @backstage/plugin-proxy-backend@0.4.3 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.7 - - @backstage/plugin-search-backend-module-pg@0.5.15 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.38 - @backstage/plugin-todo-backend@0.3.4 - - @backstage/catalog-client@1.4.5 - - @backstage/config@1.1.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 - - @backstage/plugin-events-node@0.2.15 - @backstage/plugin-permission-common@0.7.9 - - @backstage/plugin-search-common@1.2.7 -## 0.2.88-next.2 +## 0.0.16-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-nomad-backend@0.1.8-next.2 - - @backstage/backend-common@0.19.8-next.2 - @backstage/plugin-scaffolder-backend@1.18.0-next.2 - @backstage/plugin-techdocs-backend@1.8.0-next.2 - @backstage/plugin-auth-node@0.4.0-next.2 - @backstage/plugin-catalog-backend@1.14.0-next.2 - - @backstage/catalog-model@1.4.3-next.0 - - @backstage/integration@1.7.1-next.1 - @backstage/plugin-kubernetes-backend@0.12.3-next.2 - @backstage/plugin-jenkins-backend@0.2.9-next.2 - - @backstage/plugin-auth-backend@0.19.3-next.2 + - @backstage/backend-defaults@0.2.6-next.2 - @backstage/backend-tasks@0.5.11-next.2 - @backstage/plugin-adr-backend@0.4.3-next.2 - @backstage/plugin-app-backend@0.3.54-next.2 - @backstage/plugin-azure-devops-backend@0.4.3-next.2 - - @backstage/plugin-azure-sites-backend@0.1.16-next.2 - @backstage/plugin-badges-backend@0.3.3-next.2 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3-next.2 - - @backstage/plugin-catalog-node@1.4.7-next.2 - - @backstage/plugin-code-coverage-backend@0.2.20-next.2 - @backstage/plugin-devtools-backend@0.2.3-next.2 - @backstage/plugin-entity-feedback-backend@0.2.3-next.2 - - @backstage/plugin-events-backend@0.2.15-next.2 - - @backstage/plugin-explore-backend@0.0.16-next.2 - - @backstage/plugin-graphql-backend@0.1.44-next.2 - - @backstage/plugin-kafka-backend@0.3.3-next.2 - @backstage/plugin-lighthouse-backend@0.3.3-next.2 - @backstage/plugin-linguist-backend@0.5.3-next.2 - @backstage/plugin-permission-backend@0.5.29-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.3-next.2 - @backstage/plugin-permission-node@0.7.17-next.2 - @backstage/plugin-playlist-backend@0.3.10-next.2 - @backstage/plugin-proxy-backend@0.4.3-next.2 - - @backstage/plugin-rollbar-backend@0.1.51-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.7-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.23-next.2 - @backstage/plugin-search-backend@1.4.6-next.2 - @backstage/plugin-search-backend-module-catalog@0.1.10-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.9-next.2 - @backstage/plugin-search-backend-module-explore@0.1.10-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.15-next.2 - @backstage/plugin-search-backend-module-techdocs@0.1.10-next.2 - @backstage/plugin-search-backend-node@1.2.10-next.2 - - @backstage/plugin-tech-insights-backend@0.5.20-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.38-next.2 - - @backstage/plugin-tech-insights-node@0.4.12-next.2 + - @backstage/plugin-sonarqube-backend@0.2.8-next.2 - @backstage/plugin-todo-backend@0.3.4-next.2 - - example-app@0.2.88-next.2 - - @backstage/catalog-client@1.4.5-next.0 - - @backstage/config@1.1.1-next.0 + - @backstage/backend-plugin-api@0.6.6-next.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3-next.2 - - @backstage/plugin-events-node@0.2.15-next.2 - @backstage/plugin-permission-common@0.7.9-next.0 - - @backstage/plugin-search-common@1.2.7-next.0 -## 0.2.88-next.1 +## 0.0.16-next.1 ### Patch Changes - Updated dependencies - @backstage/backend-tasks@0.5.10-next.1 - @backstage/plugin-catalog-backend@1.14.0-next.1 - - @backstage/plugin-catalog-node@1.4.6-next.1 - - @backstage/backend-common@0.19.7-next.1 - @backstage/plugin-scaffolder-backend@1.18.0-next.1 - @backstage/plugin-badges-backend@0.3.2-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 - @backstage/plugin-lighthouse-backend@0.3.2-next.1 - @backstage/plugin-linguist-backend@0.5.2-next.1 - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 - @backstage/plugin-search-backend-node@1.2.9-next.1 - - @backstage/plugin-tech-insights-backend@0.5.19-next.1 - - @backstage/plugin-tech-insights-node@0.4.11-next.1 - - example-app@0.2.88-next.1 - - @backstage/plugin-auth-backend@0.19.2-next.1 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 - @backstage/plugin-kubernetes-backend@0.12.2-next.1 - @backstage/plugin-todo-backend@0.3.3-next.1 + - @backstage/backend-defaults@0.2.5-next.1 - @backstage/plugin-adr-backend@0.4.2-next.1 - @backstage/plugin-app-backend@0.3.53-next.1 - @backstage/plugin-auth-node@0.3.2-next.1 - @backstage/plugin-azure-devops-backend@0.4.2-next.1 - - @backstage/plugin-azure-sites-backend@0.1.15-next.1 - - @backstage/plugin-code-coverage-backend@0.2.19-next.1 - @backstage/plugin-devtools-backend@0.2.2-next.1 - @backstage/plugin-entity-feedback-backend@0.2.2-next.1 - - @backstage/plugin-events-backend@0.2.14-next.1 - - @backstage/plugin-explore-backend@0.0.15-next.1 - - @backstage/plugin-graphql-backend@0.1.43-next.1 - - @backstage/plugin-jenkins-backend@0.2.8-next.1 - - @backstage/plugin-kafka-backend@0.3.2-next.1 - - @backstage/plugin-nomad-backend@0.1.7-next.1 - @backstage/plugin-permission-backend@0.5.28-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.1 - @backstage/plugin-permission-node@0.7.16-next.1 - @backstage/plugin-playlist-backend@0.3.9-next.1 - @backstage/plugin-proxy-backend@0.4.2-next.1 - - @backstage/plugin-rollbar-backend@0.1.50-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.1 - @backstage/plugin-search-backend@1.4.5-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.14-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.1 + - @backstage/plugin-sonarqube-backend@0.2.7-next.1 - @backstage/plugin-techdocs-backend@1.7.2-next.1 - - @backstage/config@1.1.0 - - @backstage/catalog-client@1.4.4 - - @backstage/catalog-model@1.4.2 - - @backstage/integration@1.7.1-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 - - @backstage/plugin-events-node@0.2.14-next.1 - @backstage/plugin-permission-common@0.7.8 - - @backstage/plugin-search-common@1.2.6 -## 0.2.88-next.0 +## 0.0.16-next.0 ### Patch Changes - Updated dependencies - - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.0 - - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-sonarqube-backend@0.2.7-next.0 - @backstage/plugin-playlist-backend@0.3.9-next.0 - - @backstage/plugin-rollbar-backend@0.1.50-next.0 - @backstage/plugin-catalog-backend@1.14.0-next.0 - - @backstage/plugin-tech-insights-backend@0.5.19-next.0 - - @backstage/plugin-code-coverage-backend@0.2.19-next.0 - @backstage/plugin-auth-node@0.3.2-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.0 - - @backstage/backend-common@0.19.7-next.0 - - example-app@0.2.88-next.0 - @backstage/plugin-adr-backend@0.4.2-next.0 - @backstage/plugin-scaffolder-backend@1.17.3-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.0 - @backstage/plugin-techdocs-backend@1.7.2-next.0 - @backstage/plugin-todo-backend@0.3.3-next.0 - - @backstage/config@1.1.0 + - @backstage/backend-defaults@0.2.5-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 - @backstage/backend-tasks@0.5.10-next.0 - - @backstage/catalog-client@1.4.4 - - @backstage/catalog-model@1.4.2 - @backstage/plugin-app-backend@0.3.53-next.0 - - @backstage/plugin-auth-backend@0.19.2-next.0 - @backstage/plugin-azure-devops-backend@0.4.2-next.0 - - @backstage/plugin-azure-sites-backend@0.1.15-next.0 - @backstage/plugin-badges-backend@0.3.2-next.0 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 - - @backstage/plugin-catalog-node@1.4.6-next.0 - @backstage/plugin-devtools-backend@0.2.2-next.0 - @backstage/plugin-entity-feedback-backend@0.2.2-next.0 - - @backstage/plugin-events-backend@0.2.14-next.0 - - @backstage/plugin-events-node@0.2.14-next.0 - - @backstage/plugin-explore-backend@0.0.15-next.0 - - @backstage/plugin-graphql-backend@0.1.43-next.0 - - @backstage/plugin-jenkins-backend@0.2.8-next.0 - - @backstage/plugin-kafka-backend@0.3.2-next.0 - @backstage/plugin-kubernetes-backend@0.12.2-next.0 - @backstage/plugin-lighthouse-backend@0.3.2-next.0 - @backstage/plugin-linguist-backend@0.5.2-next.0 - - @backstage/plugin-nomad-backend@0.1.7-next.0 - @backstage/plugin-permission-backend@0.5.28-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.0 - @backstage/plugin-permission-common@0.7.8 - @backstage/plugin-permission-node@0.7.16-next.0 - @backstage/plugin-proxy-backend@0.4.2-next.0 - @backstage/plugin-search-backend@1.4.5-next.0 - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.14-next.0 - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 - @backstage/plugin-search-backend-node@1.2.9-next.0 - - @backstage/plugin-search-common@1.2.6 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.0 - - @backstage/plugin-tech-insights-node@0.4.11-next.0 -## 0.2.87 +## 0.0.15 ### Patch Changes - Updated dependencies - - @backstage/plugin-search-backend-module-pg@0.5.12 - @backstage/plugin-catalog-backend@1.13.0 - @backstage/plugin-kubernetes-backend@0.12.0 - @backstage/plugin-techdocs-backend@1.7.0 - - @backstage/plugin-auth-backend@0.19.0 - @backstage/plugin-proxy-backend@0.4.0 - @backstage/plugin-adr-backend@0.4.0 - @backstage/plugin-azure-devops-backend@0.4.0 @@ -1905,49 +1544,27 @@ - @backstage/plugin-catalog-backend-module-unprocessed@0.3.0 - @backstage/plugin-devtools-backend@0.2.0 - @backstage/plugin-entity-feedback-backend@0.2.0 - - @backstage/plugin-kafka-backend@0.3.0 - @backstage/plugin-lighthouse-backend@0.3.0 - @backstage/plugin-linguist-backend@0.5.0 - @backstage/plugin-todo-backend@0.3.0 - @backstage/plugin-app-backend@0.3.51 - - @backstage/plugin-events-backend@0.2.12 - @backstage/plugin-permission-backend@0.5.26 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.0 - @backstage/plugin-scaffolder-backend@1.17.0 - @backstage/plugin-search-backend@1.4.3 - @backstage/plugin-search-backend-module-catalog@0.1.7 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.6 - @backstage/plugin-search-backend-module-explore@0.1.7 - @backstage/plugin-search-backend-module-techdocs@0.1.7 - - @backstage/plugin-code-coverage-backend@0.2.17 - @backstage/backend-tasks@0.5.8 - - @backstage/backend-common@0.19.5 - @backstage/plugin-auth-node@0.3.0 - - @backstage/config@1.1.0 - - @backstage/catalog-client@1.4.4 - - @backstage/catalog-model@1.4.2 - - @backstage/integration@1.7.0 - @backstage/plugin-permission-common@0.7.8 - - @backstage/plugin-search-common@1.2.6 - @backstage/plugin-permission-node@0.7.14 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35 + - @backstage/backend-plugin-api@0.6.3 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0 - - @backstage/plugin-tech-insights-backend@0.5.17 - - example-app@0.2.87 - - @backstage/plugin-catalog-node@1.4.4 - - @backstage/plugin-playlist-backend@0.3.7 - - @backstage/plugin-rollbar-backend@0.1.48 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4 - - @backstage/plugin-azure-sites-backend@0.1.13 - - @backstage/plugin-events-node@0.2.12 - - @backstage/plugin-explore-backend@0.0.13 - - @backstage/plugin-graphql-backend@0.1.41 - - @backstage/plugin-jenkins-backend@0.2.6 - - @backstage/plugin-nomad-backend@0.1.5 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.20 + - @backstage/backend-defaults@0.2.3 - @backstage/plugin-search-backend-node@1.2.7 - - @backstage/plugin-tech-insights-node@0.4.9 -## 0.2.87-next.3 +## 0.0.15-next.3 ### Patch Changes @@ -1955,388 +1572,230 @@ - @backstage/plugin-techdocs-backend@1.7.0-next.3 - @backstage/plugin-proxy-backend@0.4.0-next.3 - @backstage/plugin-adr-backend@0.4.0-next.3 - - @backstage/plugin-auth-backend@0.19.0-next.3 - @backstage/plugin-azure-devops-backend@0.4.0-next.3 - @backstage/plugin-badges-backend@0.3.0-next.3 - @backstage/plugin-catalog-backend-module-unprocessed@0.3.0-next.3 - @backstage/plugin-devtools-backend@0.2.0-next.3 - @backstage/plugin-entity-feedback-backend@0.2.0-next.3 - - @backstage/plugin-kafka-backend@0.3.0-next.3 - @backstage/plugin-lighthouse-backend@0.3.0-next.3 - @backstage/plugin-linguist-backend@0.5.0-next.3 - @backstage/plugin-todo-backend@0.3.0-next.3 - @backstage/plugin-app-backend@0.3.51-next.3 - @backstage/plugin-catalog-backend@1.13.0-next.3 - - @backstage/plugin-events-backend@0.2.12-next.3 - @backstage/plugin-kubernetes-backend@0.11.6-next.3 - @backstage/plugin-permission-backend@0.5.26-next.3 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.0-next.1 - @backstage/plugin-scaffolder-backend@1.17.0-next.3 - @backstage/plugin-search-backend@1.4.3-next.3 - @backstage/plugin-search-backend-module-catalog@0.1.7-next.3 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.6-next.3 - @backstage/plugin-search-backend-module-explore@0.1.7-next.3 - - @backstage/plugin-search-backend-module-pg@0.5.12-next.3 - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.3 - - @backstage/catalog-client@1.4.4-next.2 - - @backstage/catalog-model@1.4.2-next.2 - - @backstage/config@1.1.0-next.2 - - @backstage/integration@1.7.0-next.3 - @backstage/plugin-permission-common@0.7.8-next.2 - - @backstage/plugin-search-common@1.2.6-next.2 - @backstage/plugin-permission-node@0.7.14-next.3 + - @backstage/backend-plugin-api@0.6.3-next.3 - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0-next.0 - - example-app@0.2.87-next.3 - - @backstage/backend-common@0.19.5-next.3 - - @backstage/plugin-explore-backend@0.0.13-next.3 + - @backstage/backend-defaults@0.2.3-next.3 - @backstage/backend-tasks@0.5.8-next.3 - @backstage/plugin-auth-node@0.3.0-next.3 - - @backstage/plugin-azure-sites-backend@0.1.13-next.3 - - @backstage/plugin-catalog-node@1.4.4-next.3 - - @backstage/plugin-code-coverage-backend@0.2.17-next.3 - - @backstage/plugin-events-node@0.2.12-next.3 - - @backstage/plugin-graphql-backend@0.1.41-next.3 - - @backstage/plugin-jenkins-backend@0.2.6-next.3 - - @backstage/plugin-nomad-backend@0.1.5-next.3 - - @backstage/plugin-playlist-backend@0.3.7-next.3 - - @backstage/plugin-rollbar-backend@0.1.48-next.3 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4-next.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.20-next.3 - @backstage/plugin-search-backend-node@1.2.7-next.3 - - @backstage/plugin-tech-insights-backend@0.5.17-next.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35-next.3 - - @backstage/plugin-tech-insights-node@0.4.9-next.3 -## 0.2.87-next.2 +## 0.0.15-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.16.6-next.2 - - @backstage/plugin-code-coverage-backend@0.2.17-next.2 - @backstage/plugin-permission-backend@0.5.26-next.2 - @backstage/plugin-catalog-backend@1.13.0-next.2 - @backstage/plugin-badges-backend@0.2.6-next.2 - - @backstage/config@1.1.0-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35-next.2 - - @backstage/plugin-tech-insights-backend@0.5.17-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.0-next.0 - @backstage/backend-tasks@0.5.8-next.2 - - example-app@0.2.87-next.2 - - @backstage/backend-common@0.19.5-next.2 + - @backstage/backend-defaults@0.2.3-next.2 - @backstage/plugin-app-backend@0.3.51-next.2 - - @backstage/plugin-auth-backend@0.18.9-next.2 - @backstage/plugin-auth-node@0.3.0-next.2 - - @backstage/plugin-catalog-node@1.4.4-next.2 - @backstage/plugin-entity-feedback-backend@0.1.9-next.2 - - @backstage/plugin-events-backend@0.2.12-next.2 - @backstage/plugin-kubernetes-backend@0.11.6-next.2 - @backstage/plugin-linguist-backend@0.4.3-next.2 - @backstage/plugin-permission-node@0.7.14-next.2 - - @backstage/plugin-playlist-backend@0.3.7-next.2 - @backstage/plugin-proxy-backend@0.3.3-next.2 - - @backstage/plugin-rollbar-backend@0.1.48-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4-next.2 - @backstage/plugin-search-backend@1.4.3-next.2 - @backstage/plugin-search-backend-module-catalog@0.1.7-next.2 - @backstage/plugin-search-backend-module-explore@0.1.7-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.12-next.2 - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.2 - @backstage/plugin-techdocs-backend@1.7.0-next.2 - - @backstage/integration@1.7.0-next.2 - @backstage/plugin-devtools-backend@0.1.6-next.2 - - @backstage/catalog-model@1.4.2-next.1 + - @backstage/backend-plugin-api@0.6.3-next.2 - @backstage/plugin-adr-backend@0.3.9-next.2 - @backstage/plugin-azure-devops-backend@0.3.30-next.2 - - @backstage/plugin-azure-sites-backend@0.1.13-next.2 - - @backstage/plugin-explore-backend@0.0.13-next.2 - - @backstage/plugin-graphql-backend@0.1.41-next.2 - - @backstage/plugin-jenkins-backend@0.2.6-next.2 - - @backstage/plugin-kafka-backend@0.2.44-next.2 - @backstage/plugin-lighthouse-backend@0.2.7-next.2 - - @backstage/plugin-nomad-backend@0.1.5-next.2 - @backstage/plugin-permission-common@0.7.8-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.20-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.6-next.2 - @backstage/plugin-search-backend-node@1.2.7-next.2 - - @backstage/plugin-tech-insights-node@0.4.9-next.2 - @backstage/plugin-todo-backend@0.2.3-next.2 - - @backstage/catalog-client@1.4.4-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.2.3-next.2 - - @backstage/plugin-events-node@0.2.12-next.2 - - @backstage/plugin-search-common@1.2.6-next.1 -## 0.2.87-next.1 +## 0.0.15-next.1 ### Patch Changes - Updated dependencies - - @backstage/plugin-search-backend-module-pg@0.5.12-next.1 - @backstage/plugin-kubernetes-backend@0.11.6-next.1 - @backstage/plugin-catalog-backend@1.13.0-next.1 - - @backstage/plugin-auth-backend@0.18.9-next.1 - - @backstage/config@1.1.0-next.0 - - @backstage/integration@1.7.0-next.1 - @backstage/plugin-devtools-backend@0.1.6-next.1 - @backstage/backend-tasks@0.5.8-next.1 - @backstage/plugin-techdocs-backend@1.7.0-next.1 - @backstage/plugin-scaffolder-backend@1.16.6-next.1 - - @backstage/plugin-code-coverage-backend@0.2.17-next.1 - - example-app@0.2.87-next.1 - - @backstage/backend-common@0.19.5-next.1 - - @backstage/catalog-model@1.4.2-next.0 + - @backstage/backend-plugin-api@0.6.3-next.1 - @backstage/plugin-adr-backend@0.3.9-next.1 - @backstage/plugin-app-backend@0.3.51-next.1 - @backstage/plugin-auth-node@0.3.0-next.1 - @backstage/plugin-azure-devops-backend@0.3.30-next.1 - - @backstage/plugin-azure-sites-backend@0.1.13-next.1 - @backstage/plugin-badges-backend@0.2.6-next.1 - @backstage/plugin-entity-feedback-backend@0.1.9-next.1 - - @backstage/plugin-events-backend@0.2.12-next.1 - - @backstage/plugin-explore-backend@0.0.13-next.1 - - @backstage/plugin-graphql-backend@0.1.41-next.1 - - @backstage/plugin-jenkins-backend@0.2.6-next.1 - - @backstage/plugin-kafka-backend@0.2.44-next.1 - @backstage/plugin-lighthouse-backend@0.2.7-next.1 - @backstage/plugin-linguist-backend@0.4.3-next.1 - - @backstage/plugin-nomad-backend@0.1.5-next.1 - @backstage/plugin-permission-backend@0.5.26-next.1 - @backstage/plugin-permission-common@0.7.8-next.0 - @backstage/plugin-permission-node@0.7.14-next.1 - - @backstage/plugin-playlist-backend@0.3.7-next.1 - @backstage/plugin-proxy-backend@0.3.3-next.1 - - @backstage/plugin-rollbar-backend@0.1.48-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.20-next.1 - @backstage/plugin-search-backend@1.4.3-next.1 - @backstage/plugin-search-backend-module-catalog@0.1.7-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.6-next.1 - @backstage/plugin-search-backend-module-explore@0.1.7-next.1 - @backstage/plugin-search-backend-module-techdocs@0.1.7-next.1 - @backstage/plugin-search-backend-node@1.2.7-next.1 - - @backstage/plugin-tech-insights-backend@0.5.17-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35-next.1 - - @backstage/plugin-tech-insights-node@0.4.9-next.1 - @backstage/plugin-todo-backend@0.2.3-next.1 - - @backstage/plugin-catalog-node@1.4.4-next.1 + - @backstage/backend-defaults@0.2.3-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.2.3-next.1 - - @backstage/plugin-events-node@0.2.12-next.1 - - @backstage/catalog-client@1.4.4-next.0 - - @backstage/plugin-search-common@1.2.6-next.0 -## 0.2.87-next.0 +## 0.0.15-next.0 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.12.2-next.0 - - @backstage/plugin-auth-backend@0.18.8-next.0 - - @backstage/plugin-code-coverage-backend@0.2.16-next.0 - @backstage/plugin-scaffolder-backend@1.16.3-next.0 - @backstage/plugin-auth-node@0.3.0-next.0 - - @backstage/backend-common@0.19.4-next.0 - @backstage/plugin-linguist-backend@0.4.2-next.0 - - @backstage/integration@1.7.0-next.0 - @backstage/plugin-entity-feedback-backend@0.1.8-next.0 - - @backstage/plugin-tech-insights-backend@0.5.16-next.0 - @backstage/backend-tasks@0.5.7-next.0 - @backstage/plugin-app-backend@0.3.50-next.0 - - example-app@0.2.87-next.0 - - @backstage/catalog-client@1.4.3 - - @backstage/catalog-model@1.4.1 - - @backstage/config@1.0.8 + - @backstage/backend-defaults@0.2.2-next.0 + - @backstage/backend-plugin-api@0.6.2-next.0 - @backstage/plugin-adr-backend@0.3.8-next.0 - @backstage/plugin-azure-devops-backend@0.3.29-next.0 - - @backstage/plugin-azure-sites-backend@0.1.12-next.0 - @backstage/plugin-badges-backend@0.2.5-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.2.2-next.0 - - @backstage/plugin-catalog-node@1.4.3-next.0 - @backstage/plugin-devtools-backend@0.1.5-next.0 - - @backstage/plugin-events-backend@0.2.11-next.0 - - @backstage/plugin-events-node@0.2.11-next.0 - - @backstage/plugin-explore-backend@0.0.12-next.0 - - @backstage/plugin-graphql-backend@0.1.40-next.0 - - @backstage/plugin-jenkins-backend@0.2.5-next.0 - - @backstage/plugin-kafka-backend@0.2.43-next.0 - @backstage/plugin-kubernetes-backend@0.11.5-next.0 - @backstage/plugin-lighthouse-backend@0.2.6-next.0 - - @backstage/plugin-nomad-backend@0.1.4-next.0 - @backstage/plugin-permission-backend@0.5.25-next.0 - @backstage/plugin-permission-common@0.7.7 - @backstage/plugin-permission-node@0.7.13-next.0 - - @backstage/plugin-playlist-backend@0.3.6-next.0 - @backstage/plugin-proxy-backend@0.3.2-next.0 - - @backstage/plugin-rollbar-backend@0.1.47-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.3-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.19-next.0 - @backstage/plugin-search-backend@1.4.2-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.5-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.11-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.6-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.6-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.6-next.0 - @backstage/plugin-search-backend-node@1.2.6-next.0 - - @backstage/plugin-search-common@1.2.5 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.34-next.0 - - @backstage/plugin-tech-insights-node@0.4.8-next.0 - @backstage/plugin-techdocs-backend@1.6.7-next.0 - @backstage/plugin-todo-backend@0.2.2-next.0 -## 0.2.86 +## 0.0.14 ### Patch Changes - Updated dependencies - - @backstage/plugin-search-backend-module-elasticsearch@1.3.3 - - @backstage/plugin-search-backend-module-pg@0.5.9 + - @backstage/plugin-search-backend-module-techdocs@0.1.4 + - @backstage/plugin-search-backend-module-catalog@0.1.4 + - @backstage/plugin-search-backend-module-explore@0.1.4 - @backstage/plugin-azure-devops-backend@0.3.27 - @backstage/plugin-kubernetes-backend@0.11.3 - @backstage/plugin-lighthouse-backend@0.2.4 - @backstage/plugin-permission-backend@0.5.23 - @backstage/plugin-scaffolder-backend@1.16.0 + - @backstage/backend-defaults@0.2.0 - @backstage/plugin-devtools-backend@0.1.3 - @backstage/plugin-techdocs-backend@1.6.5 - - @backstage/backend-common@0.19.2 - @backstage/plugin-catalog-backend@1.12.0 - @backstage/plugin-badges-backend@0.2.3 - - @backstage/plugin-events-backend@0.2.9 - @backstage/plugin-search-backend@1.4.0 - - @backstage/plugin-kafka-backend@0.2.41 - @backstage/plugin-proxy-backend@0.3.0 - @backstage/plugin-todo-backend@0.2.0 - @backstage/plugin-app-backend@0.3.48 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1 - - @backstage/plugin-auth-backend@0.18.6 - - @backstage/plugin-explore-backend@0.0.10 + - @backstage/backend-plugin-api@0.6.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.17 - @backstage/plugin-entity-feedback-backend@0.1.6 - - @backstage/plugin-code-coverage-backend@0.2.14 - @backstage/plugin-search-backend-node@1.2.4 - @backstage/plugin-linguist-backend@0.4.0 - - @backstage/plugin-playlist-backend@0.3.4 - - @backstage/plugin-jenkins-backend@0.2.3 - - @backstage/plugin-nomad-backend@0.1.2 - - @backstage/plugin-catalog-node@1.4.1 - - @backstage/plugin-events-node@0.2.9 - @backstage/plugin-auth-node@0.2.17 - - @backstage/integration@1.6.0 - @backstage/backend-tasks@0.5.5 - - example-app@0.2.86 - @backstage/plugin-adr-backend@0.3.6 - - @backstage/plugin-azure-sites-backend@0.1.10 - - @backstage/plugin-graphql-backend@0.1.38 - @backstage/plugin-permission-node@0.7.11 - - @backstage/plugin-rollbar-backend@0.1.45 - - @backstage/plugin-tech-insights-backend@0.5.14 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32 - - @backstage/plugin-tech-insights-node@0.4.6 - - @backstage/catalog-client@1.4.3 - - @backstage/catalog-model@1.4.1 - - @backstage/config@1.0.8 - @backstage/plugin-permission-common@0.7.7 - - @backstage/plugin-search-common@1.2.5 -## 0.2.86-next.2 +## 0.0.14-next.2 ### Patch Changes - Updated dependencies - - @backstage/plugin-auth-backend@0.18.6-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.4-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.4-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.4-next.2 - @backstage/plugin-scaffolder-backend@1.15.2-next.2 - - @backstage/plugin-explore-backend@0.0.10-next.2 - @backstage/plugin-catalog-backend@1.12.0-next.2 + - @backstage/backend-plugin-api@0.6.0-next.2 - @backstage/plugin-proxy-backend@0.3.0-next.2 - @backstage/backend-tasks@0.5.5-next.2 - @backstage/plugin-app-backend@0.3.48-next.2 - @backstage/plugin-linguist-backend@0.4.0-next.2 - @backstage/plugin-techdocs-backend@1.6.5-next.2 - - @backstage/backend-common@0.19.2-next.2 - - example-app@0.2.86-next.2 + - @backstage/backend-defaults@0.2.0-next.2 - @backstage/plugin-adr-backend@0.3.6-next.2 - @backstage/plugin-azure-devops-backend@0.3.27-next.2 - @backstage/plugin-badges-backend@0.2.3-next.2 - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.2 - - @backstage/plugin-catalog-node@1.4.1-next.2 - @backstage/plugin-devtools-backend@0.1.3-next.2 - @backstage/plugin-entity-feedback-backend@0.1.6-next.2 - - @backstage/plugin-events-backend@0.2.9-next.2 - - @backstage/plugin-events-node@0.2.9-next.2 - - @backstage/plugin-kafka-backend@0.2.41-next.2 - @backstage/plugin-kubernetes-backend@0.11.3-next.2 - @backstage/plugin-lighthouse-backend@0.2.4-next.2 - @backstage/plugin-permission-backend@0.5.23-next.2 - @backstage/plugin-permission-node@0.7.11-next.2 - @backstage/plugin-search-backend@1.4.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.3-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.9-next.2 - @backstage/plugin-search-backend-node@1.2.4-next.2 - @backstage/plugin-todo-backend@0.2.0-next.2 - - @backstage/plugin-tech-insights-backend@0.5.14-next.2 - - @backstage/plugin-tech-insights-node@0.4.6-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.17-next.2 - @backstage/plugin-auth-node@0.2.17-next.2 - - @backstage/plugin-azure-sites-backend@0.1.10-next.2 - - @backstage/plugin-code-coverage-backend@0.2.14-next.2 - - @backstage/plugin-graphql-backend@0.1.38-next.2 - - @backstage/plugin-jenkins-backend@0.2.3-next.2 - - @backstage/plugin-nomad-backend@0.1.2-next.2 - - @backstage/plugin-playlist-backend@0.3.4-next.2 - - @backstage/plugin-rollbar-backend@0.1.45-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32-next.2 -## 0.2.86-next.1 +## 0.0.14-next.1 ### Patch Changes - Updated dependencies - - @backstage/plugin-search-backend-module-elasticsearch@1.3.3-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.9-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.4-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.4-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.4-next.1 - @backstage/plugin-azure-devops-backend@0.3.27-next.1 - @backstage/plugin-kubernetes-backend@0.11.3-next.1 - @backstage/plugin-lighthouse-backend@0.2.4-next.1 - @backstage/plugin-permission-backend@0.5.23-next.1 - @backstage/plugin-scaffolder-backend@1.15.2-next.1 + - @backstage/backend-defaults@0.2.0-next.1 - @backstage/plugin-devtools-backend@0.1.3-next.1 - @backstage/plugin-techdocs-backend@1.6.5-next.1 - - @backstage/backend-common@0.19.2-next.1 - @backstage/plugin-catalog-backend@1.12.0-next.1 - @backstage/plugin-badges-backend@0.2.3-next.1 - - @backstage/plugin-events-backend@0.2.9-next.1 - @backstage/plugin-search-backend@1.4.0-next.1 - - @backstage/plugin-kafka-backend@0.2.41-next.1 - - @backstage/plugin-proxy-backend@0.2.42-next.1 - @backstage/plugin-todo-backend@0.2.0-next.1 - @backstage/plugin-app-backend@0.3.48-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.17-next.1 - @backstage/plugin-entity-feedback-backend@0.1.6-next.1 - - @backstage/plugin-code-coverage-backend@0.2.14-next.1 - @backstage/plugin-search-backend-node@1.2.4-next.1 - @backstage/plugin-linguist-backend@0.3.2-next.1 - - @backstage/plugin-playlist-backend@0.3.4-next.1 - - @backstage/plugin-explore-backend@0.0.10-next.1 - - @backstage/plugin-jenkins-backend@0.2.3-next.1 - - @backstage/plugin-nomad-backend@0.1.2-next.1 - - @backstage/plugin-catalog-node@1.4.1-next.1 - - @backstage/plugin-events-node@0.2.9-next.1 - @backstage/plugin-auth-node@0.2.17-next.1 - - @backstage/plugin-auth-backend@0.18.6-next.1 - @backstage/backend-tasks@0.5.5-next.1 - @backstage/plugin-adr-backend@0.3.6-next.1 - - @backstage/plugin-azure-sites-backend@0.1.10-next.1 - - @backstage/plugin-graphql-backend@0.1.38-next.1 - @backstage/plugin-permission-node@0.7.11-next.1 - - @backstage/plugin-rollbar-backend@0.1.45-next.1 - - @backstage/plugin-tech-insights-backend@0.5.14-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32-next.1 - - @backstage/plugin-tech-insights-node@0.4.6-next.1 - - example-app@0.2.86-next.1 - - @backstage/integration@1.5.1 - - @backstage/catalog-client@1.4.3 - - @backstage/catalog-model@1.4.1 - - @backstage/config@1.0.8 - @backstage/plugin-permission-common@0.7.7 - - @backstage/plugin-search-common@1.2.5 -## 0.2.86-next.0 +## 0.0.14-next.0 ### Patch Changes @@ -2347,61 +1806,34 @@ - @backstage/plugin-todo-backend@0.2.0-next.0 - @backstage/plugin-catalog-backend@1.12.0-next.0 - @backstage/plugin-search-backend@1.4.0-next.0 - - example-app@0.2.86-next.0 - - @backstage/backend-common@0.19.2-next.0 + - @backstage/backend-defaults@0.1.13-next.0 - @backstage/backend-tasks@0.5.5-next.0 - - @backstage/catalog-client@1.4.3 - - @backstage/catalog-model@1.4.1 - - @backstage/config@1.0.8 - - @backstage/integration@1.5.1 - @backstage/plugin-adr-backend@0.3.6-next.0 - @backstage/plugin-app-backend@0.3.48-next.0 - - @backstage/plugin-auth-backend@0.18.6-next.0 - @backstage/plugin-auth-node@0.2.17-next.0 - @backstage/plugin-azure-devops-backend@0.3.27-next.0 - - @backstage/plugin-azure-sites-backend@0.1.10-next.0 - @backstage/plugin-badges-backend@0.2.3-next.0 - - @backstage/plugin-catalog-node@1.4.1-next.0 - - @backstage/plugin-code-coverage-backend@0.2.14-next.0 - @backstage/plugin-devtools-backend@0.1.3-next.0 - @backstage/plugin-entity-feedback-backend@0.1.6-next.0 - - @backstage/plugin-events-backend@0.2.9-next.0 - - @backstage/plugin-events-node@0.2.9-next.0 - - @backstage/plugin-explore-backend@0.0.10-next.0 - - @backstage/plugin-graphql-backend@0.1.38-next.0 - - @backstage/plugin-jenkins-backend@0.2.3-next.0 - - @backstage/plugin-kafka-backend@0.2.41-next.0 - @backstage/plugin-kubernetes-backend@0.11.3-next.0 - @backstage/plugin-lighthouse-backend@0.2.4-next.0 - - @backstage/plugin-nomad-backend@0.1.2-next.0 - @backstage/plugin-permission-backend@0.5.23-next.0 - @backstage/plugin-permission-common@0.7.7 - @backstage/plugin-permission-node@0.7.11-next.0 - - @backstage/plugin-playlist-backend@0.3.4-next.0 - - @backstage/plugin-proxy-backend@0.2.42-next.0 - - @backstage/plugin-rollbar-backend@0.1.45-next.0 - @backstage/plugin-scaffolder-backend@1.15.2-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.1-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.17-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.3-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.9-next.0 - - @backstage/plugin-search-common@1.2.5 - - @backstage/plugin-tech-insights-backend@0.5.14-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.32-next.0 - - @backstage/plugin-tech-insights-node@0.4.6-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.4-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.4-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.4-next.0 - @backstage/plugin-techdocs-backend@1.6.5-next.0 -## 0.2.85 +## 0.0.13 ### Patch Changes - Updated dependencies - @backstage/plugin-kubernetes-backend@0.11.2 - @backstage/plugin-badges-backend@0.2.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.0 - @backstage/plugin-devtools-backend@0.1.2 - - @backstage/plugin-tech-insights-backend@0.5.13 - - @backstage/backend-common@0.19.1 - @backstage/plugin-scaffolder-backend@1.15.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1 - @backstage/plugin-azure-devops-backend@0.3.26 @@ -2410,98 +1842,52 @@ - @backstage/plugin-lighthouse-backend@0.2.3 - @backstage/plugin-entity-feedback-backend@0.1.5 - @backstage/plugin-catalog-backend@1.11.0 - - @backstage/plugin-catalog-node@1.4.0 - - @backstage/plugin-auth-backend@0.18.5 - - example-app@0.2.85 + - @backstage/backend-defaults@0.1.12 - @backstage/backend-tasks@0.5.4 - - @backstage/catalog-client@1.4.3 - - @backstage/catalog-model@1.4.1 - - @backstage/config@1.0.8 - - @backstage/integration@1.5.1 - @backstage/plugin-app-backend@0.3.47 - @backstage/plugin-auth-node@0.2.16 - - @backstage/plugin-azure-sites-backend@0.1.9 - - @backstage/plugin-code-coverage-backend@0.2.13 - - @backstage/plugin-events-backend@0.2.8 - - @backstage/plugin-events-node@0.2.8 - - @backstage/plugin-explore-backend@0.0.9 - - @backstage/plugin-graphql-backend@0.1.37 - - @backstage/plugin-jenkins-backend@0.2.2 - - @backstage/plugin-kafka-backend@0.2.40 - - @backstage/plugin-nomad-backend@0.1.1 - @backstage/plugin-permission-backend@0.5.22 - @backstage/plugin-permission-common@0.7.7 - @backstage/plugin-permission-node@0.7.10 - - @backstage/plugin-playlist-backend@0.3.3 - - @backstage/plugin-proxy-backend@0.2.41 - - @backstage/plugin-rollbar-backend@0.1.44 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.16 - @backstage/plugin-search-backend@1.3.3 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.2 - - @backstage/plugin-search-backend-module-pg@0.5.8 + - @backstage/plugin-search-backend-module-catalog@0.1.3 + - @backstage/plugin-search-backend-module-explore@0.1.3 + - @backstage/plugin-search-backend-module-techdocs@0.1.3 - @backstage/plugin-search-backend-node@1.2.3 - - @backstage/plugin-search-common@1.2.5 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.31 - - @backstage/plugin-tech-insights-node@0.4.5 - @backstage/plugin-techdocs-backend@1.6.4 - @backstage/plugin-todo-backend@0.1.44 -## 0.2.85-next.2 +## 0.0.13-next.2 ### Patch Changes - Updated dependencies - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.0-next.1 - @backstage/plugin-devtools-backend@0.1.2-next.2 - - @backstage/plugin-tech-insights-backend@0.5.13-next.1 - @backstage/plugin-scaffolder-backend@1.15.1-next.1 - @backstage/plugin-kubernetes-backend@0.11.2-next.2 - @backstage/plugin-adr-backend@0.3.5-next.1 - - example-app@0.2.85-next.2 - - @backstage/backend-common@0.19.1-next.0 + - @backstage/backend-defaults@0.1.12-next.0 - @backstage/backend-tasks@0.5.4-next.0 - - @backstage/catalog-client@1.4.3-next.0 - - @backstage/catalog-model@1.4.1-next.0 - - @backstage/config@1.0.8 - - @backstage/integration@1.5.1-next.0 - @backstage/plugin-app-backend@0.3.47-next.0 - - @backstage/plugin-auth-backend@0.18.5-next.1 - @backstage/plugin-auth-node@0.2.16-next.0 - @backstage/plugin-azure-devops-backend@0.3.26-next.1 - - @backstage/plugin-azure-sites-backend@0.1.9-next.0 - @backstage/plugin-badges-backend@0.2.2-next.1 - @backstage/plugin-catalog-backend@1.11.0-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1-next.0 - - @backstage/plugin-catalog-node@1.4.0-next.0 - - @backstage/plugin-code-coverage-backend@0.2.13-next.0 - @backstage/plugin-entity-feedback-backend@0.1.5-next.0 - - @backstage/plugin-events-backend@0.2.8-next.0 - - @backstage/plugin-events-node@0.2.8-next.0 - - @backstage/plugin-explore-backend@0.0.9-next.0 - - @backstage/plugin-graphql-backend@0.1.37-next.0 - - @backstage/plugin-jenkins-backend@0.2.2-next.0 - - @backstage/plugin-kafka-backend@0.2.40-next.0 - - @backstage/plugin-lighthouse-backend@0.2.3-next.0 - @backstage/plugin-linguist-backend@0.3.1-next.1 - - @backstage/plugin-nomad-backend@0.1.1-next.0 - @backstage/plugin-permission-backend@0.5.22-next.0 - @backstage/plugin-permission-common@0.7.7-next.0 - @backstage/plugin-permission-node@0.7.10-next.0 - - @backstage/plugin-playlist-backend@0.3.3-next.0 - - @backstage/plugin-proxy-backend@0.2.41-next.0 - - @backstage/plugin-rollbar-backend@0.1.44-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.16-next.1 - @backstage/plugin-search-backend@1.3.3-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.2-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.8-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.3-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.3-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.3-next.0 - @backstage/plugin-search-backend-node@1.2.3-next.0 - - @backstage/plugin-search-common@1.2.5-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.31-next.0 - - @backstage/plugin-tech-insights-node@0.4.5-next.0 - @backstage/plugin-techdocs-backend@1.6.4-next.0 - @backstage/plugin-todo-backend@0.1.44-next.0 -## 0.2.85-next.1 +## 0.0.13-next.1 ### Patch Changes @@ -2511,4340 +1897,611 @@ - @backstage/plugin-azure-devops-backend@0.3.26-next.1 - @backstage/plugin-devtools-backend@0.1.2-next.1 - @backstage/plugin-linguist-backend@0.3.1-next.1 - - @backstage/plugin-auth-backend@0.18.5-next.1 - - example-app@0.2.85-next.1 - - @backstage/config@1.0.8 -## 0.2.85-next.0 +## 0.0.13-next.0 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.19.1-next.0 - @backstage/plugin-catalog-backend-module-unprocessed@0.1.1-next.0 - @backstage/plugin-entity-feedback-backend@0.1.5-next.0 - @backstage/plugin-catalog-backend@1.11.0-next.0 - - @backstage/plugin-catalog-node@1.4.0-next.0 - @backstage/plugin-kubernetes-backend@0.11.2-next.0 - - example-app@0.2.85-next.0 - - @backstage/backend-tasks@0.5.4-next.0 - - @backstage/catalog-client@1.4.3-next.0 - - @backstage/catalog-model@1.4.1-next.0 - - @backstage/config@1.0.8 - - @backstage/integration@1.5.1-next.0 - - @backstage/plugin-adr-backend@0.3.5-next.0 + - @backstage/backend-defaults@0.1.12-next.0 - @backstage/plugin-app-backend@0.3.47-next.0 - - @backstage/plugin-auth-backend@0.18.5-next.0 - @backstage/plugin-auth-node@0.2.16-next.0 - - @backstage/plugin-azure-devops-backend@0.3.26-next.0 - - @backstage/plugin-azure-sites-backend@0.1.9-next.0 - - @backstage/plugin-badges-backend@0.2.2-next.0 - - @backstage/plugin-code-coverage-backend@0.2.13-next.0 - - @backstage/plugin-devtools-backend@0.1.2-next.0 - - @backstage/plugin-events-backend@0.2.8-next.0 - - @backstage/plugin-events-node@0.2.8-next.0 - - @backstage/plugin-explore-backend@0.0.9-next.0 - - @backstage/plugin-graphql-backend@0.1.37-next.0 - - @backstage/plugin-jenkins-backend@0.2.2-next.0 - - @backstage/plugin-kafka-backend@0.2.40-next.0 - - @backstage/plugin-lighthouse-backend@0.2.3-next.0 - - @backstage/plugin-linguist-backend@0.3.1-next.0 - - @backstage/plugin-nomad-backend@0.1.1-next.0 - @backstage/plugin-permission-backend@0.5.22-next.0 - @backstage/plugin-permission-common@0.7.7-next.0 - @backstage/plugin-permission-node@0.7.10-next.0 - - @backstage/plugin-playlist-backend@0.3.3-next.0 - - @backstage/plugin-proxy-backend@0.2.41-next.0 - - @backstage/plugin-rollbar-backend@0.1.44-next.0 - @backstage/plugin-scaffolder-backend@1.15.1-next.0 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.4-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.16-next.0 - @backstage/plugin-search-backend@1.3.3-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.2-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.8-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.3-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.3-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.3-next.0 - @backstage/plugin-search-backend-node@1.2.3-next.0 - - @backstage/plugin-search-common@1.2.5-next.0 - - @backstage/plugin-tech-insights-backend@0.5.13-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.31-next.0 - - @backstage/plugin-tech-insights-node@0.4.5-next.0 - @backstage/plugin-techdocs-backend@1.6.4-next.0 - @backstage/plugin-todo-backend@0.1.44-next.0 -## 0.2.84 +## 0.0.12 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.19.0 - - @backstage/catalog-client@1.4.2 - - @backstage/plugin-jenkins-backend@0.2.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3 - - @backstage/plugin-devtools-backend@0.1.1 - @backstage/plugin-scaffolder-backend@1.15.0 - - @backstage/plugin-nomad-backend@0.1.0 - - @backstage/plugin-azure-sites-backend@0.1.8 - @backstage/plugin-kubernetes-backend@0.11.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0 - - @backstage/plugin-badges-backend@0.2.1 - @backstage/plugin-catalog-backend@1.10.0 - - @backstage/integration@1.5.0 - @backstage/plugin-search-backend@1.3.2 - - @backstage/plugin-explore-backend@0.0.8 - - @backstage/catalog-model@1.4.0 - - @backstage/plugin-auth-backend@0.18.4 - - @backstage/plugin-adr-backend@0.3.4 - - @backstage/plugin-code-coverage-backend@0.2.12 - - @backstage/plugin-proxy-backend@0.2.40 - - @backstage/plugin-linguist-backend@0.3.0 - - @backstage/plugin-search-backend-module-pg@0.5.7 - - example-app@0.2.84 - - @backstage/backend-tasks@0.5.3 + - @backstage/plugin-search-backend-module-explore@0.1.2 + - @backstage/backend-defaults@0.1.11 - @backstage/plugin-app-backend@0.3.46 - @backstage/plugin-auth-node@0.2.15 - - @backstage/plugin-azure-devops-backend@0.3.25 - - @backstage/plugin-catalog-node@1.3.7 - - @backstage/plugin-entity-feedback-backend@0.1.4 - - @backstage/plugin-events-backend@0.2.7 - - @backstage/plugin-graphql-backend@0.1.36 - - @backstage/plugin-kafka-backend@0.2.39 - - @backstage/plugin-lighthouse-backend@0.2.2 - @backstage/plugin-permission-backend@0.5.21 - @backstage/plugin-permission-node@0.7.9 - - @backstage/plugin-playlist-backend@0.3.2 - - @backstage/plugin-rollbar-backend@0.1.43 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.15 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.1 + - @backstage/plugin-search-backend-module-catalog@0.1.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.2 - @backstage/plugin-search-backend-node@1.2.2 - - @backstage/plugin-tech-insights-backend@0.5.12 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30 - - @backstage/plugin-tech-insights-node@0.4.4 - @backstage/plugin-techdocs-backend@1.6.3 - @backstage/plugin-todo-backend@0.1.43 - - @backstage/config@1.0.8 - - @backstage/plugin-events-node@0.2.7 - @backstage/plugin-permission-common@0.7.6 - - @backstage/plugin-search-common@1.2.4 -## 0.2.84-next.3 +## 0.0.12-next.3 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.15.0-next.3 - @backstage/plugin-kubernetes-backend@0.11.1-next.3 - - @backstage/backend-common@0.19.0-next.2 - - @backstage/catalog-model@1.4.0-next.1 - @backstage/plugin-catalog-backend@1.10.0-next.2 - - example-app@0.2.84-next.3 - - @backstage/backend-tasks@0.5.3-next.2 - - @backstage/catalog-client@1.4.2-next.2 - - @backstage/config@1.0.7 - - @backstage/integration@1.5.0-next.0 - - @backstage/plugin-adr-backend@0.3.4-next.2 + - @backstage/backend-defaults@0.1.11-next.2 - @backstage/plugin-app-backend@0.3.46-next.2 - - @backstage/plugin-auth-backend@0.18.4-next.3 - @backstage/plugin-auth-node@0.2.15-next.2 - - @backstage/plugin-azure-devops-backend@0.3.25-next.2 - - @backstage/plugin-azure-sites-backend@0.1.8-next.2 - - @backstage/plugin-badges-backend@0.2.1-next.3 - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0-next.1 - - @backstage/plugin-catalog-node@1.3.7-next.2 - - @backstage/plugin-code-coverage-backend@0.2.12-next.3 - - @backstage/plugin-devtools-backend@0.1.1-next.2 - - @backstage/plugin-entity-feedback-backend@0.1.4-next.2 - - @backstage/plugin-events-backend@0.2.7-next.2 - - @backstage/plugin-events-node@0.2.7-next.2 - - @backstage/plugin-explore-backend@0.0.8-next.2 - - @backstage/plugin-graphql-backend@0.1.36-next.2 - - @backstage/plugin-jenkins-backend@0.2.1-next.2 - - @backstage/plugin-kafka-backend@0.2.39-next.2 - - @backstage/plugin-lighthouse-backend@0.2.2-next.2 - - @backstage/plugin-linguist-backend@0.3.0-next.2 - @backstage/plugin-permission-backend@0.5.21-next.2 - @backstage/plugin-permission-common@0.7.6-next.0 - @backstage/plugin-permission-node@0.7.9-next.2 - - @backstage/plugin-playlist-backend@0.3.2-next.2 - - @backstage/plugin-proxy-backend@0.2.40-next.2 - - @backstage/plugin-rollbar-backend@0.1.43-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3-next.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.3 - @backstage/plugin-search-backend@1.3.2-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.1-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.7-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.2-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.2-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.2-next.2 - @backstage/plugin-search-backend-node@1.2.2-next.2 - - @backstage/plugin-search-common@1.2.4-next.0 - - @backstage/plugin-tech-insights-backend@0.5.12-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30-next.2 - - @backstage/plugin-tech-insights-node@0.4.4-next.2 - @backstage/plugin-techdocs-backend@1.6.3-next.2 - @backstage/plugin-todo-backend@0.1.43-next.2 -## 0.2.84-next.2 +## 0.0.12-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-kubernetes-backend@0.11.1-next.2 - - @backstage/plugin-badges-backend@0.2.1-next.2 - @backstage/plugin-scaffolder-backend@1.15.0-next.2 - - @backstage/plugin-auth-backend@0.18.4-next.2 - - @backstage/plugin-code-coverage-backend@0.2.12-next.2 - - example-app@0.2.84-next.2 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.2 - - @backstage/config@1.0.7 -## 0.2.84-next.1 +## 0.0.12-next.1 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.19.0-next.1 - - @backstage/plugin-jenkins-backend@0.2.1-next.1 - - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.1.3-next.1 - - @backstage/plugin-devtools-backend@0.1.1-next.1 - @backstage/plugin-catalog-backend-module-unprocessed@0.1.0-next.0 - @backstage/plugin-catalog-backend@1.9.2-next.1 - - @backstage/integration@1.5.0-next.0 - - @backstage/plugin-adr-backend@0.3.4-next.1 - - @backstage/plugin-proxy-backend@0.2.40-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.7-next.1 - - @backstage/catalog-model@1.4.0-next.0 - @backstage/plugin-scaffolder-backend@1.15.0-next.1 - - @backstage/backend-tasks@0.5.3-next.1 + - @backstage/backend-defaults@0.1.11-next.1 - @backstage/plugin-app-backend@0.3.46-next.1 - - @backstage/plugin-auth-backend@0.18.4-next.1 - @backstage/plugin-auth-node@0.2.15-next.1 - - @backstage/plugin-azure-devops-backend@0.3.25-next.1 - - @backstage/plugin-azure-sites-backend@0.1.8-next.1 - - @backstage/plugin-badges-backend@0.2.1-next.1 - - @backstage/plugin-catalog-node@1.3.7-next.1 - - @backstage/plugin-code-coverage-backend@0.2.12-next.1 - - @backstage/plugin-entity-feedback-backend@0.1.4-next.1 - - @backstage/plugin-events-backend@0.2.7-next.1 - - @backstage/plugin-explore-backend@0.0.8-next.1 - - @backstage/plugin-graphql-backend@0.1.36-next.1 - - @backstage/plugin-kafka-backend@0.2.39-next.1 - @backstage/plugin-kubernetes-backend@0.11.1-next.1 - - @backstage/plugin-lighthouse-backend@0.2.2-next.1 - - @backstage/plugin-linguist-backend@0.3.0-next.1 - @backstage/plugin-permission-backend@0.5.21-next.1 - @backstage/plugin-permission-node@0.7.9-next.1 - - @backstage/plugin-playlist-backend@0.3.2-next.1 - - @backstage/plugin-rollbar-backend@0.1.43-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.1 - @backstage/plugin-search-backend@1.3.2-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.1-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.2-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.2-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.2-next.1 - @backstage/plugin-search-backend-node@1.2.2-next.1 - - @backstage/plugin-tech-insights-backend@0.5.12-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30-next.1 - - @backstage/plugin-tech-insights-node@0.4.4-next.1 - @backstage/plugin-techdocs-backend@1.6.3-next.1 - @backstage/plugin-todo-backend@0.1.43-next.1 - - example-app@0.2.84-next.1 - - @backstage/catalog-client@1.4.2-next.1 - @backstage/plugin-permission-common@0.7.6-next.0 - - @backstage/plugin-events-node@0.2.7-next.1 - - @backstage/config@1.0.7 - - @backstage/plugin-search-common@1.2.4-next.0 -## 0.2.84-next.0 +## 0.0.12-next.0 ### Patch Changes - Updated dependencies - - @backstage/catalog-client@1.4.2-next.0 - @backstage/plugin-scaffolder-backend@1.14.1-next.0 - - @backstage/plugin-jenkins-backend@0.2.1-next.0 - - @backstage/plugin-linguist-backend@0.3.0-next.0 - - @backstage/plugin-devtools-backend@0.1.1-next.0 - - @backstage/plugin-adr-backend@0.3.4-next.0 - - @backstage/plugin-auth-backend@0.18.4-next.0 - - @backstage/plugin-badges-backend@0.2.1-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.2-next.0 - @backstage/plugin-catalog-backend@1.9.2-next.0 - - @backstage/plugin-catalog-node@1.3.7-next.0 - - @backstage/plugin-code-coverage-backend@0.2.12-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.4-next.0 - @backstage/plugin-kubernetes-backend@0.11.1-next.0 - - @backstage/plugin-lighthouse-backend@0.2.2-next.0 - - @backstage/plugin-playlist-backend@0.3.2-next.0 - - @backstage/plugin-tech-insights-backend@0.5.12-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.2-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.2-next.0 - @backstage/plugin-techdocs-backend@1.6.3-next.0 - @backstage/plugin-todo-backend@0.1.43-next.0 - - example-app@0.2.84-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.15-next.0 - - @backstage/backend-common@0.18.6-next.0 - - @backstage/integration@1.4.5 - @backstage/plugin-app-backend@0.3.46-next.0 - - @backstage/plugin-explore-backend@0.0.8-next.0 - - @backstage/config@1.0.7 - - @backstage/backend-tasks@0.5.3-next.0 - - @backstage/catalog-model@1.3.0 + - @backstage/backend-defaults@0.1.11-next.0 - @backstage/plugin-auth-node@0.2.15-next.0 - - @backstage/plugin-azure-devops-backend@0.3.25-next.0 - - @backstage/plugin-azure-sites-backend@0.1.8-next.0 - - @backstage/plugin-events-backend@0.2.7-next.0 - - @backstage/plugin-events-node@0.2.7-next.0 - - @backstage/plugin-graphql-backend@0.1.36-next.0 - - @backstage/plugin-kafka-backend@0.2.39-next.0 - @backstage/plugin-permission-backend@0.5.21-next.0 - @backstage/plugin-permission-common@0.7.5 - @backstage/plugin-permission-node@0.7.9-next.0 - - @backstage/plugin-proxy-backend@0.2.40-next.0 - - @backstage/plugin-rollbar-backend@0.1.43-next.0 - @backstage/plugin-search-backend@1.3.2-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.1-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.7-next.0 - @backstage/plugin-search-backend-node@1.2.2-next.0 - - @backstage/plugin-search-common@1.2.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.30-next.0 - - @backstage/plugin-tech-insights-node@0.4.4-next.0 -## 0.2.83 +## 0.0.11 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.14.0 - - @backstage/plugin-devtools-backend@0.1.0 - @backstage/plugin-catalog-backend@1.9.1 - - @backstage/backend-common@0.18.5 - @backstage/plugin-kubernetes-backend@0.11.0 - - @backstage/plugin-auth-backend@0.18.3 - - @backstage/plugin-badges-backend@0.2.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.0 - - @backstage/integration@1.4.5 - @backstage/plugin-todo-backend@0.1.42 - - @backstage/plugin-jenkins-backend@0.2.0 - - @backstage/plugin-azure-sites-backend@0.1.7 - @backstage/plugin-permission-node@0.7.8 - @backstage/plugin-search-backend@1.3.1 - - example-app@0.2.83 - - @backstage/backend-tasks@0.5.2 + - @backstage/backend-defaults@0.1.10 - @backstage/plugin-app-backend@0.3.45 - @backstage/plugin-auth-node@0.2.14 - - @backstage/plugin-catalog-node@1.3.6 - - @backstage/plugin-entity-feedback-backend@0.1.3 - - @backstage/plugin-events-backend@0.2.6 - - @backstage/plugin-playlist-backend@0.3.1 - - @backstage/plugin-rollbar-backend@0.1.42 - - @backstage/plugin-search-backend-module-pg@0.5.6 - - @backstage/plugin-tech-insights-backend@0.5.11 + - @backstage/plugin-search-backend-module-catalog@0.1.1 + - @backstage/plugin-search-backend-module-explore@0.1.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.1 - @backstage/plugin-techdocs-backend@1.6.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.14 - - @backstage/plugin-adr-backend@0.3.3 - - @backstage/plugin-azure-devops-backend@0.3.24 - - @backstage/plugin-code-coverage-backend@0.2.11 - - @backstage/plugin-explore-backend@0.0.7 - - @backstage/plugin-graphql-backend@0.1.35 - - @backstage/plugin-kafka-backend@0.2.38 - - @backstage/plugin-lighthouse-backend@0.2.1 - - @backstage/plugin-linguist-backend@0.2.2 - @backstage/plugin-permission-backend@0.5.20 - - @backstage/plugin-proxy-backend@0.2.39 - @backstage/plugin-search-backend-node@1.2.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.29 - - @backstage/plugin-tech-insights-node@0.4.3 - - @backstage/catalog-client@1.4.1 - - @backstage/catalog-model@1.3.0 - - @backstage/config@1.0.7 - - @backstage/plugin-events-node@0.2.6 - @backstage/plugin-permission-common@0.7.5 - - @backstage/plugin-search-common@1.2.3 -## 0.2.83-next.2 +## 0.0.11-next.2 ### Patch Changes - Updated dependencies - - @backstage/plugin-devtools-backend@0.1.0-next.0 - @backstage/plugin-catalog-backend@1.9.1-next.2 - - @backstage/plugin-badges-backend@0.2.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.3.0-next.2 - @backstage/plugin-kubernetes-backend@0.11.0-next.2 - - @backstage/plugin-auth-backend@0.18.3-next.2 - @backstage/plugin-search-backend@1.3.1-next.2 - - example-app@0.2.83-next.2 - @backstage/plugin-scaffolder-backend@1.13.2-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.14-next.2 - - @backstage/config@1.0.7 -## 0.2.83-next.1 +## 0.0.11-next.1 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.18.5-next.1 - @backstage/plugin-kubernetes-backend@0.11.0-next.1 - @backstage/plugin-catalog-backend@1.9.1-next.1 - - @backstage/plugin-jenkins-backend@0.1.35-next.1 - @backstage/plugin-scaffolder-backend@1.13.2-next.1 - - example-app@0.2.83-next.1 - - @backstage/backend-tasks@0.5.2-next.1 - - @backstage/plugin-adr-backend@0.3.3-next.1 + - @backstage/backend-defaults@0.1.10-next.1 - @backstage/plugin-app-backend@0.3.45-next.1 - - @backstage/plugin-auth-backend@0.18.3-next.1 - @backstage/plugin-auth-node@0.2.14-next.1 - - @backstage/plugin-azure-devops-backend@0.3.24-next.1 - - @backstage/plugin-azure-sites-backend@0.1.7-next.1 - - @backstage/plugin-badges-backend@0.1.39-next.1 - - @backstage/plugin-catalog-node@1.3.6-next.1 - - @backstage/plugin-code-coverage-backend@0.2.11-next.1 - - @backstage/plugin-entity-feedback-backend@0.1.3-next.1 - - @backstage/plugin-events-backend@0.2.6-next.1 - - @backstage/plugin-explore-backend@0.0.7-next.1 - - @backstage/plugin-graphql-backend@0.1.35-next.1 - - @backstage/plugin-kafka-backend@0.2.38-next.1 - - @backstage/plugin-lighthouse-backend@0.2.1-next.1 - - @backstage/plugin-linguist-backend@0.2.2-next.1 - @backstage/plugin-permission-backend@0.5.20-next.1 - @backstage/plugin-permission-node@0.7.8-next.1 - - @backstage/plugin-playlist-backend@0.3.1-next.1 - - @backstage/plugin-proxy-backend@0.2.39-next.1 - - @backstage/plugin-rollbar-backend@0.1.42-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.14-next.1 - @backstage/plugin-search-backend@1.3.1-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.2.1-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.6-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.1-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.1-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.1-next.1 - @backstage/plugin-search-backend-node@1.2.1-next.1 - - @backstage/plugin-tech-insights-backend@0.5.11-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.29-next.1 - - @backstage/plugin-tech-insights-node@0.4.3-next.1 - @backstage/plugin-techdocs-backend@1.6.2-next.1 - @backstage/plugin-todo-backend@0.1.42-next.1 - - @backstage/config@1.0.7 - - @backstage/plugin-events-node@0.2.6-next.1 -## 0.2.83-next.0 +## 0.0.11-next.0 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.18.5-next.0 - - @backstage/integration@1.4.5-next.0 - @backstage/plugin-permission-node@0.7.8-next.0 - @backstage/plugin-scaffolder-backend@1.13.2-next.0 - @backstage/plugin-kubernetes-backend@0.11.0-next.0 - - @backstage/backend-tasks@0.5.2-next.0 + - @backstage/backend-defaults@0.1.10-next.0 - @backstage/plugin-app-backend@0.3.45-next.0 - - @backstage/plugin-auth-backend@0.18.3-next.0 - @backstage/plugin-auth-node@0.2.14-next.0 - @backstage/plugin-catalog-backend@1.9.1-next.0 - - @backstage/plugin-catalog-node@1.3.6-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.3-next.0 - - @backstage/plugin-events-backend@0.2.6-next.0 - - @backstage/plugin-playlist-backend@0.3.1-next.0 - - @backstage/plugin-rollbar-backend@0.1.42-next.0 - @backstage/plugin-search-backend@1.3.1-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.6-next.0 - - @backstage/plugin-tech-insights-backend@0.5.11-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.1-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.1-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.1-next.0 - @backstage/plugin-techdocs-backend@1.6.2-next.0 - - example-app@0.2.83-next.0 - - @backstage/plugin-adr-backend@0.3.3-next.0 - - @backstage/plugin-azure-devops-backend@0.3.24-next.0 - - @backstage/plugin-azure-sites-backend@0.1.7-next.0 - - @backstage/plugin-badges-backend@0.1.39-next.0 - - @backstage/plugin-code-coverage-backend@0.2.11-next.0 - - @backstage/plugin-explore-backend@0.0.7-next.0 - - @backstage/plugin-graphql-backend@0.1.35-next.0 - - @backstage/plugin-jenkins-backend@0.1.35-next.0 - - @backstage/plugin-kafka-backend@0.2.38-next.0 - - @backstage/plugin-lighthouse-backend@0.2.1-next.0 - - @backstage/plugin-linguist-backend@0.2.2-next.0 - @backstage/plugin-permission-backend@0.5.20-next.0 - - @backstage/plugin-proxy-backend@0.2.39-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.14-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.2.1-next.0 - @backstage/plugin-search-backend-node@1.2.1-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.29-next.0 - - @backstage/plugin-tech-insights-node@0.4.3-next.0 - @backstage/plugin-todo-backend@0.1.42-next.0 - - @backstage/catalog-client@1.4.1 - - @backstage/catalog-model@1.3.0 - - @backstage/config@1.0.7 - - @backstage/plugin-events-node@0.2.6-next.0 - @backstage/plugin-permission-common@0.7.5 - - @backstage/plugin-search-common@1.2.3 -## 0.2.82 +## 0.0.10 ### Patch Changes - Updated dependencies - @backstage/plugin-kubernetes-backend@0.10.0 - - @backstage/backend-common@0.18.4 - @backstage/plugin-scaffolder-backend@1.13.0 - @backstage/plugin-catalog-backend@1.9.0 - - @backstage/plugin-code-coverage-backend@0.2.10 - - @backstage/catalog-client@1.4.1 - @backstage/plugin-permission-node@0.7.7 - @backstage/plugin-permission-backend@0.5.19 - - @backstage/plugin-entity-feedback-backend@0.1.2 - - @backstage/plugin-rollbar-backend@0.1.41 - @backstage/plugin-search-backend@1.3.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.2.0 - - @backstage/plugin-search-backend-module-pg@0.5.5 - - @backstage/plugin-auth-backend@0.18.2 - - @backstage/plugin-lighthouse-backend@0.2.0 - @backstage/plugin-permission-common@0.7.5 - - @backstage/plugin-playlist-backend@0.3.0 - - @backstage/backend-tasks@0.5.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28 - - @backstage/plugin-adr-backend@0.3.2 - - @backstage/plugin-graphql-backend@0.1.34 - - @backstage/catalog-model@1.3.0 - @backstage/plugin-techdocs-backend@1.6.1 - - @backstage/plugin-explore-backend@0.0.6 - - @backstage/plugin-events-backend@0.2.5 - @backstage/plugin-search-backend-node@1.2.0 - - @backstage/integration@1.4.4 - - example-app@0.2.82 + - @backstage/plugin-search-backend-module-techdocs@0.1.0 + - @backstage/plugin-search-backend-module-catalog@0.1.0 + - @backstage/plugin-search-backend-module-explore@0.1.0 + - @backstage/backend-defaults@0.1.9 - @backstage/plugin-app-backend@0.3.44 - @backstage/plugin-auth-node@0.2.13 - - @backstage/plugin-azure-devops-backend@0.3.23 - - @backstage/plugin-azure-sites-backend@0.1.6 - - @backstage/plugin-badges-backend@0.1.38 - - @backstage/plugin-catalog-node@1.3.5 - - @backstage/plugin-jenkins-backend@0.1.34 - - @backstage/plugin-kafka-backend@0.2.37 - - @backstage/plugin-linguist-backend@0.2.1 - - @backstage/plugin-proxy-backend@0.2.38 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.12 - - @backstage/plugin-tech-insights-backend@0.5.10 - - @backstage/plugin-tech-insights-node@0.4.2 - @backstage/plugin-todo-backend@0.1.41 - - @backstage/config@1.0.7 - - @backstage/plugin-events-node@0.2.5 - - @backstage/plugin-search-common@1.2.3 -## 0.2.82-next.3 +## 0.0.10-next.3 ### Patch Changes - Updated dependencies - @backstage/plugin-kubernetes-backend@0.10.0-next.3 - @backstage/plugin-catalog-backend@1.9.0-next.3 - - @backstage/plugin-code-coverage-backend@0.2.10-next.3 - - @backstage/plugin-lighthouse-backend@0.2.0-next.3 - - @backstage/plugin-auth-backend@0.18.2-next.3 - @backstage/plugin-scaffolder-backend@1.13.0-next.3 - - @backstage/plugin-search-backend-module-elasticsearch@1.2.0-next.3 - - @backstage/catalog-model@1.3.0-next.0 - - @backstage/plugin-events-backend@0.2.5-next.3 - - example-app@0.2.82-next.3 - - @backstage/backend-common@0.18.4-next.2 - - @backstage/backend-tasks@0.5.1-next.2 - - @backstage/catalog-client@1.4.1-next.1 - - @backstage/config@1.0.7 - - @backstage/integration@1.4.4-next.0 - - @backstage/plugin-adr-backend@0.3.2-next.3 + - @backstage/backend-defaults@0.1.9-next.2 - @backstage/plugin-app-backend@0.3.44-next.2 - @backstage/plugin-auth-node@0.2.13-next.2 - - @backstage/plugin-azure-devops-backend@0.3.23-next.2 - - @backstage/plugin-azure-sites-backend@0.1.6-next.2 - - @backstage/plugin-badges-backend@0.1.38-next.3 - - @backstage/plugin-catalog-node@1.3.5-next.3 - - @backstage/plugin-entity-feedback-backend@0.1.2-next.3 - - @backstage/plugin-events-node@0.2.5-next.2 - - @backstage/plugin-explore-backend@0.0.6-next.2 - - @backstage/plugin-graphql-backend@0.1.34-next.3 - - @backstage/plugin-jenkins-backend@0.1.34-next.3 - - @backstage/plugin-kafka-backend@0.2.37-next.3 - - @backstage/plugin-linguist-backend@0.2.1-next.3 - @backstage/plugin-permission-backend@0.5.19-next.2 - @backstage/plugin-permission-common@0.7.5-next.0 - @backstage/plugin-permission-node@0.7.7-next.2 - - @backstage/plugin-playlist-backend@0.2.7-next.3 - - @backstage/plugin-proxy-backend@0.2.38-next.2 - - @backstage/plugin-rollbar-backend@0.1.41-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.3 - @backstage/plugin-search-backend@1.3.0-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.5-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.0-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.0-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.0-next.2 - @backstage/plugin-search-backend-node@1.2.0-next.2 - - @backstage/plugin-search-common@1.2.3-next.0 - - @backstage/plugin-tech-insights-backend@0.5.10-next.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.2 - - @backstage/plugin-tech-insights-node@0.4.2-next.2 - @backstage/plugin-techdocs-backend@1.6.1-next.3 - @backstage/plugin-todo-backend@0.1.41-next.3 -## 0.2.82-next.2 +## 0.0.10-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-kubernetes-backend@0.10.0-next.2 - @backstage/plugin-catalog-backend@1.8.1-next.2 - - @backstage/backend-common@0.18.4-next.2 - - @backstage/catalog-client@1.4.1-next.0 - @backstage/plugin-permission-node@0.7.7-next.2 - @backstage/plugin-permission-backend@0.5.19-next.2 - - @backstage/plugin-rollbar-backend@0.1.41-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.2 - @backstage/plugin-scaffolder-backend@1.13.0-next.2 - - example-app@0.2.82-next.2 - - @backstage/backend-tasks@0.5.1-next.2 - - @backstage/catalog-model@1.2.1 - - @backstage/config@1.0.7 - - @backstage/integration@1.4.4-next.0 - - @backstage/plugin-adr-backend@0.3.2-next.2 + - @backstage/backend-defaults@0.1.9-next.2 - @backstage/plugin-app-backend@0.3.44-next.2 - - @backstage/plugin-auth-backend@0.18.2-next.2 - @backstage/plugin-auth-node@0.2.13-next.2 - - @backstage/plugin-azure-devops-backend@0.3.23-next.2 - - @backstage/plugin-azure-sites-backend@0.1.6-next.2 - - @backstage/plugin-badges-backend@0.1.38-next.2 - - @backstage/plugin-catalog-node@1.3.5-next.2 - - @backstage/plugin-code-coverage-backend@0.2.10-next.2 - - @backstage/plugin-entity-feedback-backend@0.1.2-next.2 - - @backstage/plugin-events-backend@0.2.5-next.2 - - @backstage/plugin-events-node@0.2.5-next.2 - - @backstage/plugin-explore-backend@0.0.6-next.2 - - @backstage/plugin-graphql-backend@0.1.34-next.2 - - @backstage/plugin-jenkins-backend@0.1.34-next.2 - - @backstage/plugin-kafka-backend@0.2.37-next.2 - - @backstage/plugin-lighthouse-backend@0.1.2-next.2 - - @backstage/plugin-linguist-backend@0.2.1-next.2 - @backstage/plugin-permission-common@0.7.5-next.0 - - @backstage/plugin-playlist-backend@0.2.7-next.2 - - @backstage/plugin-proxy-backend@0.2.38-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.2 - @backstage/plugin-search-backend@1.3.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.2.0-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.5-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.0-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.0-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.0-next.1 - @backstage/plugin-search-backend-node@1.2.0-next.2 - - @backstage/plugin-search-common@1.2.3-next.0 - - @backstage/plugin-tech-insights-backend@0.5.10-next.2 - - @backstage/plugin-tech-insights-node@0.4.2-next.2 - @backstage/plugin-techdocs-backend@1.6.1-next.2 - @backstage/plugin-todo-backend@0.1.41-next.2 -## 0.2.82-next.1 +## 0.0.10-next.1 ### Patch Changes - Updated dependencies - @backstage/plugin-search-backend@1.3.0-next.1 - @backstage/plugin-scaffolder-backend@1.13.0-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.2.0-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.5-next.1 - - @backstage/plugin-permission-node@0.7.7-next.1 - - @backstage/plugin-permission-backend@0.5.19-next.1 - - @backstage/plugin-permission-common@0.7.5-next.0 - - @backstage/plugin-playlist-backend@0.2.7-next.1 - @backstage/plugin-catalog-backend@1.8.1-next.1 - - @backstage/backend-tasks@0.5.1-next.1 - - @backstage/plugin-adr-backend@0.3.2-next.1 - @backstage/plugin-kubernetes-backend@0.10.0-next.1 - @backstage/plugin-techdocs-backend@1.6.1-next.1 - - @backstage/plugin-explore-backend@0.0.6-next.1 - @backstage/plugin-search-backend-node@1.2.0-next.1 - - @backstage/integration@1.4.4-next.0 - - @backstage/plugin-auth-backend@0.18.2-next.1 - - example-app@0.2.82-next.1 - - @backstage/backend-common@0.18.4-next.1 - - @backstage/catalog-client@1.4.0 - - @backstage/catalog-model@1.2.1 - - @backstage/config@1.0.7 + - @backstage/plugin-search-backend-module-techdocs@0.1.0-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.0-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.0-next.0 + - @backstage/backend-defaults@0.1.9-next.1 - @backstage/plugin-app-backend@0.3.44-next.1 - - @backstage/plugin-auth-node@0.2.13-next.1 - - @backstage/plugin-azure-devops-backend@0.3.23-next.1 - - @backstage/plugin-azure-sites-backend@0.1.6-next.1 - - @backstage/plugin-badges-backend@0.1.38-next.1 - - @backstage/plugin-catalog-node@1.3.5-next.1 - - @backstage/plugin-code-coverage-backend@0.2.10-next.1 - - @backstage/plugin-entity-feedback-backend@0.1.2-next.1 - - @backstage/plugin-events-backend@0.2.5-next.1 - - @backstage/plugin-events-node@0.2.5-next.1 - - @backstage/plugin-graphql-backend@0.1.34-next.1 - - @backstage/plugin-jenkins-backend@0.1.34-next.1 - - @backstage/plugin-kafka-backend@0.2.37-next.1 - - @backstage/plugin-lighthouse-backend@0.1.2-next.1 - - @backstage/plugin-linguist-backend@0.2.1-next.1 - - @backstage/plugin-proxy-backend@0.2.38-next.1 - - @backstage/plugin-rollbar-backend@0.1.41-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.1 - - @backstage/plugin-search-common@1.2.3-next.0 - - @backstage/plugin-tech-insights-backend@0.5.10-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.1 - - @backstage/plugin-tech-insights-node@0.4.2-next.1 - @backstage/plugin-todo-backend@0.1.41-next.1 -## 0.2.82-next.0 +## 0.0.10-next.0 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.12.1-next.0 - - @backstage/plugin-kubernetes-backend@0.10.0-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.2-next.0 - - @backstage/plugin-auth-backend@0.18.2-next.0 - @backstage/plugin-catalog-backend@1.8.1-next.0 - - @backstage/plugin-graphql-backend@0.1.34-next.0 - - @backstage/backend-common@0.18.4-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.0 - - example-app@0.2.82-next.0 - - @backstage/config@1.0.7 - - @backstage/integration@1.4.3 - - @backstage/backend-tasks@0.5.1-next.0 - - @backstage/catalog-client@1.4.0 - - @backstage/catalog-model@1.2.1 - - @backstage/plugin-adr-backend@0.3.2-next.0 + - @backstage/backend-defaults@0.1.9-next.0 - @backstage/plugin-app-backend@0.3.44-next.0 - - @backstage/plugin-auth-node@0.2.13-next.0 - - @backstage/plugin-azure-devops-backend@0.3.23-next.0 - - @backstage/plugin-azure-sites-backend@0.1.6-next.0 - - @backstage/plugin-badges-backend@0.1.38-next.0 - - @backstage/plugin-catalog-node@1.3.5-next.0 - - @backstage/plugin-code-coverage-backend@0.2.10-next.0 - - @backstage/plugin-events-backend@0.2.5-next.0 - - @backstage/plugin-events-node@0.2.5-next.0 - - @backstage/plugin-explore-backend@0.0.6-next.0 - - @backstage/plugin-jenkins-backend@0.1.34-next.0 - - @backstage/plugin-kafka-backend@0.2.37-next.0 - - @backstage/plugin-lighthouse-backend@0.1.2-next.0 - - @backstage/plugin-linguist-backend@0.2.1-next.0 - - @backstage/plugin-permission-backend@0.5.19-next.0 - - @backstage/plugin-permission-common@0.7.4 - - @backstage/plugin-permission-node@0.7.7-next.0 - - @backstage/plugin-playlist-backend@0.2.7-next.0 - - @backstage/plugin-proxy-backend@0.2.38-next.0 - - @backstage/plugin-rollbar-backend@0.1.41-next.0 - - @backstage/plugin-search-backend@1.2.5-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.5-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.5-next.0 - - @backstage/plugin-search-backend-node@1.1.5-next.0 - - @backstage/plugin-search-common@1.2.2 - - @backstage/plugin-tech-insights-backend@0.5.10-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.0 - - @backstage/plugin-tech-insights-node@0.4.2-next.0 - @backstage/plugin-techdocs-backend@1.6.1-next.0 - @backstage/plugin-todo-backend@0.1.41-next.0 -## 0.2.81 +## 0.0.9 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.12.0 - @backstage/plugin-catalog-backend@1.8.0 - - @backstage/catalog-client@1.4.0 - @backstage/plugin-todo-backend@0.1.40 - - @backstage/plugin-permission-node@0.7.6 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.4 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27 - - @backstage/plugin-auth-node@0.2.12 - @backstage/plugin-techdocs-backend@1.6.0 - - @backstage/backend-tasks@0.5.0 - - @backstage/plugin-tech-insights-backend@0.5.9 - - @backstage/plugin-adr-backend@0.3.1 - - @backstage/plugin-auth-backend@0.18.1 - - @backstage/backend-common@0.18.3 - - @backstage/plugin-linguist-backend@0.2.0 - - @backstage/plugin-catalog-node@1.3.4 - - @backstage/catalog-model@1.2.1 - - @backstage/plugin-events-backend@0.2.4 + - @backstage/backend-defaults@0.1.8 - @backstage/plugin-app-backend@0.3.43 - - @backstage/plugin-events-node@0.2.4 - - @backstage/integration@1.4.3 - - @backstage/plugin-azure-devops-backend@0.3.22 - - @backstage/plugin-azure-sites-backend@0.1.5 - - @backstage/plugin-code-coverage-backend@0.2.9 - - @backstage/plugin-entity-feedback-backend@0.1.1 - - @backstage/plugin-explore-backend@0.0.5 - - @backstage/plugin-graphql-backend@0.1.33 - - @backstage/plugin-jenkins-backend@0.1.33 - - @backstage/plugin-kubernetes-backend@0.9.4 - - @backstage/plugin-permission-backend@0.5.18 - - @backstage/plugin-permission-common@0.7.4 - - @backstage/plugin-playlist-backend@0.2.6 - - @backstage/plugin-proxy-backend@0.2.37 - - @backstage/plugin-rollbar-backend@0.1.40 - - @backstage/plugin-lighthouse-backend@0.1.1 - - @backstage/config@1.0.7 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.11 - - @backstage/plugin-badges-backend@0.1.37 - - example-app@0.2.81 - - @backstage/plugin-search-backend@1.2.4 - - @backstage/plugin-kafka-backend@0.2.36 - - @backstage/plugin-search-backend-module-pg@0.5.4 - - @backstage/plugin-search-backend-node@1.1.4 - - @backstage/plugin-search-common@1.2.2 - - @backstage/plugin-tech-insights-node@0.4.1 -## 0.2.81-next.2 +## 0.0.9-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.12.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.4-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27-next.2 - - @backstage/plugin-auth-node@0.2.12-next.2 - - @backstage/backend-tasks@0.5.0-next.2 - - @backstage/plugin-adr-backend@0.3.1-next.2 - - @backstage/backend-common@0.18.3-next.2 - - @backstage/plugin-linguist-backend@0.2.0-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.11-next.2 - - example-app@0.2.81-next.2 - - @backstage/plugin-techdocs-backend@1.5.4-next.2 - - @backstage/plugin-auth-backend@0.18.1-next.2 - - @backstage/plugin-entity-feedback-backend@0.1.1-next.2 - - @backstage/plugin-jenkins-backend@0.1.33-next.2 - - @backstage/plugin-kubernetes-backend@0.9.4-next.2 - - @backstage/plugin-permission-backend@0.5.18-next.2 - - @backstage/plugin-permission-node@0.7.6-next.2 - - @backstage/plugin-playlist-backend@0.2.6-next.2 - - @backstage/plugin-search-backend@1.2.4-next.2 - - @backstage/plugin-lighthouse-backend@0.1.1-next.2 - - @backstage/plugin-search-backend-node@1.1.4-next.2 - - @backstage/plugin-tech-insights-backend@0.5.9-next.2 - - @backstage/plugin-tech-insights-node@0.4.1-next.2 + - @backstage/backend-defaults@0.1.8-next.2 - @backstage/plugin-app-backend@0.3.43-next.2 - - @backstage/plugin-azure-devops-backend@0.3.22-next.2 - - @backstage/plugin-azure-sites-backend@0.1.5-next.2 - - @backstage/plugin-badges-backend@0.1.37-next.2 - @backstage/plugin-catalog-backend@1.8.0-next.2 - - @backstage/plugin-catalog-node@1.3.4-next.2 - - @backstage/plugin-code-coverage-backend@0.2.9-next.2 - - @backstage/plugin-events-backend@0.2.4-next.2 - - @backstage/plugin-explore-backend@0.0.5-next.2 - - @backstage/plugin-graphql-backend@0.1.33-next.2 - - @backstage/plugin-kafka-backend@0.2.36-next.2 - - @backstage/plugin-proxy-backend@0.2.37-next.2 - - @backstage/plugin-rollbar-backend@0.1.40-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.4-next.2 - @backstage/plugin-todo-backend@0.1.40-next.2 - - @backstage/plugin-events-node@0.2.4-next.2 - - @backstage/config@1.0.7-next.0 - - @backstage/integration@1.4.3-next.0 -## 0.2.81-next.1 +## 0.0.9-next.1 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.12.0-next.1 - - @backstage/plugin-permission-node@0.7.6-next.1 - - @backstage/plugin-techdocs-backend@1.5.4-next.1 - - @backstage/plugin-auth-backend@0.18.1-next.1 - - @backstage/backend-common@0.18.3-next.1 - - @backstage/catalog-client@1.4.0-next.1 - - @backstage/integration@1.4.3-next.0 - - @backstage/plugin-adr-backend@0.3.1-next.1 - @backstage/plugin-app-backend@0.3.43-next.1 - - @backstage/plugin-auth-node@0.2.12-next.1 - - @backstage/plugin-azure-devops-backend@0.3.22-next.1 - - @backstage/plugin-azure-sites-backend@0.1.5-next.1 - @backstage/plugin-catalog-backend@1.8.0-next.1 - - @backstage/plugin-code-coverage-backend@0.2.9-next.1 - - @backstage/plugin-entity-feedback-backend@0.1.1-next.1 - - @backstage/plugin-explore-backend@0.0.5-next.1 - - @backstage/plugin-graphql-backend@0.1.33-next.1 - - @backstage/plugin-jenkins-backend@0.1.33-next.1 - - @backstage/plugin-kubernetes-backend@0.9.4-next.1 - - @backstage/plugin-linguist-backend@0.2.0-next.1 - - @backstage/plugin-permission-backend@0.5.18-next.1 - - @backstage/plugin-permission-common@0.7.4-next.0 - - @backstage/plugin-playlist-backend@0.2.6-next.1 - - @backstage/plugin-proxy-backend@0.2.37-next.1 - - @backstage/plugin-rollbar-backend@0.1.40-next.1 - @backstage/plugin-todo-backend@0.1.40-next.1 - - @backstage/plugin-lighthouse-backend@0.1.1-next.1 - - @backstage/backend-tasks@0.4.4-next.1 - - @backstage/config@1.0.7-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.11-next.1 - - @backstage/plugin-search-backend@1.2.4-next.1 - - example-app@0.2.81-next.1 - - @backstage/catalog-model@1.2.1-next.1 - - @backstage/plugin-badges-backend@0.1.37-next.1 - - @backstage/plugin-catalog-node@1.3.4-next.1 - - @backstage/plugin-events-backend@0.2.4-next.1 - - @backstage/plugin-events-node@0.2.4-next.1 - - @backstage/plugin-kafka-backend@0.2.36-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.4-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.4-next.1 - - @backstage/plugin-search-backend-node@1.1.4-next.1 - - @backstage/plugin-search-common@1.2.2-next.0 - - @backstage/plugin-tech-insights-backend@0.5.9-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27-next.1 - - @backstage/plugin-tech-insights-node@0.4.1-next.1 + - @backstage/backend-defaults@0.1.8-next.1 -## 0.2.81-next.0 +## 0.0.9-next.0 ### Patch Changes - Updated dependencies - - @backstage/catalog-client@1.4.0-next.0 - @backstage/plugin-todo-backend@0.1.40-next.0 - @backstage/plugin-scaffolder-backend@1.11.1-next.0 - @backstage/plugin-catalog-backend@1.8.0-next.0 - - @backstage/plugin-tech-insights-backend@0.5.9-next.0 - - @backstage/plugin-linguist-backend@0.2.0-next.0 - - @backstage/plugin-adr-backend@0.3.1-next.0 - - @backstage/backend-tasks@0.4.4-next.0 - - @backstage/plugin-techdocs-backend@1.5.4-next.0 - - @backstage/backend-common@0.18.3-next.0 - - @backstage/catalog-model@1.2.1-next.0 - - @backstage/plugin-events-backend@0.2.4-next.0 - - @backstage/plugin-catalog-node@1.3.4-next.0 + - @backstage/backend-defaults@0.1.8-next.0 - @backstage/plugin-app-backend@0.3.43-next.0 - - @backstage/plugin-events-node@0.2.4-next.0 - - @backstage/plugin-proxy-backend@0.2.37-next.0 - - @backstage/plugin-auth-backend@0.18.1-next.0 - - @backstage/plugin-badges-backend@0.1.37-next.0 - - @backstage/plugin-code-coverage-backend@0.2.9-next.0 - - @backstage/plugin-entity-feedback-backend@0.1.1-next.0 - - @backstage/plugin-jenkins-backend@0.1.33-next.0 - - @backstage/plugin-kubernetes-backend@0.9.4-next.0 - - @backstage/plugin-lighthouse-backend@0.1.1-next.0 - - @backstage/plugin-playlist-backend@0.2.6-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.11-next.0 - - example-app@0.2.81-next.0 - - @backstage/config@1.0.6 - - @backstage/integration@1.4.2 - - @backstage/plugin-auth-node@0.2.12-next.0 - - @backstage/plugin-azure-devops-backend@0.3.22-next.0 - - @backstage/plugin-azure-sites-backend@0.1.5-next.0 - - @backstage/plugin-explore-backend@0.0.5-next.0 - - @backstage/plugin-graphql-backend@0.1.33-next.0 - - @backstage/plugin-kafka-backend@0.2.36-next.0 - - @backstage/plugin-permission-backend@0.5.18-next.0 - - @backstage/plugin-permission-common@0.7.3 - - @backstage/plugin-permission-node@0.7.6-next.0 - - @backstage/plugin-rollbar-backend@0.1.40-next.0 - - @backstage/plugin-search-backend@1.2.4-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.4-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.4-next.0 - - @backstage/plugin-search-backend-node@1.1.4-next.0 - - @backstage/plugin-search-common@1.2.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27-next.0 - - @backstage/plugin-tech-insights-node@0.4.1-next.0 -## 0.2.80 +## 0.0.8 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.7.2 - - @backstage/plugin-playlist-backend@0.2.5 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.3 - - @backstage/backend-common@0.18.2 - - @backstage/plugin-kubernetes-backend@0.9.3 - - @backstage/plugin-lighthouse-backend@0.1.0 - - @backstage/plugin-code-coverage-backend@0.2.8 - - @backstage/plugin-azure-devops-backend@0.3.21 - - @backstage/plugin-azure-sites-backend@0.1.4 - - @backstage/plugin-adr-backend@0.3.0 - - @backstage/plugin-tech-insights-backend@0.5.8 - - @backstage/plugin-tech-insights-node@0.4.0 - - @backstage/plugin-entity-feedback-backend@0.1.0 - - @backstage/plugin-search-backend@1.2.3 - - @backstage/plugin-techdocs-backend@1.5.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.10 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26 - @backstage/plugin-scaffolder-backend@1.11.0 - - @backstage/plugin-events-backend@0.2.3 - - @backstage/plugin-kafka-backend@0.2.35 - - @backstage/plugin-proxy-backend@0.2.36 - @backstage/plugin-app-backend@0.3.42 - - @backstage/catalog-model@1.2.0 - - @backstage/plugin-auth-backend@0.18.0 - - @backstage/plugin-linguist-backend@0.1.0 - - @backstage/plugin-events-node@0.2.3 - - example-app@0.2.80 - - @backstage/plugin-catalog-node@1.3.3 - - @backstage/backend-tasks@0.4.3 - - @backstage/catalog-client@1.3.1 - - @backstage/config@1.0.6 - - @backstage/integration@1.4.2 - - @backstage/plugin-auth-node@0.2.11 - - @backstage/plugin-badges-backend@0.1.36 - - @backstage/plugin-explore-backend@0.0.4 - - @backstage/plugin-graphql-backend@0.1.32 - - @backstage/plugin-jenkins-backend@0.1.32 - - @backstage/plugin-permission-backend@0.5.17 - - @backstage/plugin-permission-common@0.7.3 - - @backstage/plugin-permission-node@0.7.5 - - @backstage/plugin-rollbar-backend@0.1.39 - - @backstage/plugin-search-backend-module-pg@0.5.3 - - @backstage/plugin-search-backend-node@1.1.3 - - @backstage/plugin-search-common@1.2.1 - - @backstage/plugin-todo-backend@0.1.39 + - @backstage/backend-defaults@0.1.7 -## 0.2.80-next.2 +## 0.0.8-next.2 ### Patch Changes - Updated dependencies - - @backstage/plugin-lighthouse-backend@0.1.0-next.0 - - @backstage/backend-common@0.18.2-next.2 - @backstage/plugin-catalog-backend@1.7.2-next.2 - - @backstage/plugin-search-backend@1.2.3-next.2 - @backstage/plugin-scaffolder-backend@1.11.0-next.2 - - @backstage/plugin-events-backend@0.2.3-next.2 - - @backstage/plugin-kafka-backend@0.2.35-next.2 - - @backstage/plugin-proxy-backend@0.2.36-next.2 - @backstage/plugin-app-backend@0.3.42-next.2 - - @backstage/catalog-model@1.2.0-next.1 - - @backstage/plugin-kubernetes-backend@0.9.3-next.2 - - @backstage/plugin-events-node@0.2.3-next.2 - - @backstage/plugin-catalog-node@1.3.3-next.2 - - @backstage/backend-tasks@0.4.3-next.2 - - @backstage/plugin-auth-backend@0.17.5-next.2 - - @backstage/plugin-auth-node@0.2.11-next.2 - - @backstage/plugin-permission-node@0.7.5-next.2 - - @backstage/plugin-playlist-backend@0.2.5-next.2 - - @backstage/plugin-rollbar-backend@0.1.39-next.2 - - @backstage/plugin-search-backend-module-pg@0.5.3-next.2 - - @backstage/plugin-tech-insights-backend@0.5.8-next.2 - - @backstage/plugin-techdocs-backend@1.5.3-next.2 - - example-app@0.2.80-next.2 - - @backstage/catalog-client@1.3.1-next.1 - - @backstage/config@1.0.6 - - @backstage/integration@1.4.2 - - @backstage/plugin-adr-backend@0.2.7-next.2 - - @backstage/plugin-azure-devops-backend@0.3.21-next.2 - - @backstage/plugin-azure-sites-backend@0.1.4-next.2 - - @backstage/plugin-badges-backend@0.1.36-next.2 - - @backstage/plugin-code-coverage-backend@0.2.8-next.2 - - @backstage/plugin-explore-backend@0.0.4-next.2 - - @backstage/plugin-graphql-backend@0.1.32-next.2 - - @backstage/plugin-jenkins-backend@0.1.32-next.2 - - @backstage/plugin-permission-backend@0.5.17-next.2 - - @backstage/plugin-permission-common@0.7.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.2 - - @backstage/plugin-search-backend-node@1.1.3-next.2 - - @backstage/plugin-search-common@1.2.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.2 - - @backstage/plugin-tech-insights-node@0.4.0-next.2 - - @backstage/plugin-todo-backend@0.1.39-next.2 + - @backstage/backend-defaults@0.1.7-next.2 -## 0.2.80-next.1 +## 0.0.8-next.1 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.7.2-next.1 - - @backstage/plugin-tech-insights-backend@0.5.8-next.1 - - @backstage/plugin-tech-insights-node@0.4.0-next.1 - - @backstage/plugin-azure-devops-backend@0.3.21-next.1 - - @backstage/backend-common@0.18.2-next.1 - - @backstage/plugin-kubernetes-backend@0.9.3-next.1 - @backstage/plugin-scaffolder-backend@1.11.0-next.1 - - @backstage/plugin-playlist-backend@0.2.5-next.1 - - example-app@0.2.80-next.1 - - @backstage/backend-tasks@0.4.3-next.1 - - @backstage/catalog-client@1.3.1-next.0 - - @backstage/catalog-model@1.1.6-next.0 - - @backstage/config@1.0.6 - - @backstage/integration@1.4.2 - - @backstage/plugin-adr-backend@0.2.7-next.1 + - @backstage/backend-defaults@0.1.7-next.1 - @backstage/plugin-app-backend@0.3.42-next.1 - - @backstage/plugin-auth-backend@0.17.5-next.1 - - @backstage/plugin-auth-node@0.2.11-next.1 - - @backstage/plugin-azure-sites-backend@0.1.4-next.1 - - @backstage/plugin-badges-backend@0.1.36-next.1 - - @backstage/plugin-catalog-node@1.3.3-next.1 - - @backstage/plugin-code-coverage-backend@0.2.8-next.1 - - @backstage/plugin-events-backend@0.2.3-next.1 - - @backstage/plugin-events-node@0.2.3-next.1 - - @backstage/plugin-explore-backend@0.0.4-next.1 - - @backstage/plugin-graphql-backend@0.1.32-next.1 - - @backstage/plugin-jenkins-backend@0.1.32-next.1 - - @backstage/plugin-kafka-backend@0.2.35-next.1 - - @backstage/plugin-permission-backend@0.5.17-next.1 - - @backstage/plugin-permission-common@0.7.3 - - @backstage/plugin-permission-node@0.7.5-next.1 - - @backstage/plugin-proxy-backend@0.2.36-next.1 - - @backstage/plugin-rollbar-backend@0.1.39-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.1 - - @backstage/plugin-search-backend@1.2.3-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.3-next.1 - - @backstage/plugin-search-backend-node@1.1.3-next.1 - - @backstage/plugin-search-common@1.2.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.1 - - @backstage/plugin-techdocs-backend@1.5.3-next.1 - - @backstage/plugin-todo-backend@0.1.39-next.1 -## 0.2.80-next.0 +## 0.0.8-next.0 ### Patch Changes - Updated dependencies - - @backstage/plugin-kubernetes-backend@0.9.3-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.0 - @backstage/plugin-scaffolder-backend@1.11.0-next.0 - - @backstage/catalog-model@1.1.6-next.0 - - example-app@0.2.80-next.0 - - @backstage/plugin-techdocs-backend@1.5.3-next.0 - - @backstage/backend-common@0.18.2-next.0 + - @backstage/backend-defaults@0.1.7-next.0 - @backstage/plugin-app-backend@0.3.42-next.0 - - @backstage/catalog-client@1.3.1-next.0 - - @backstage/plugin-adr-backend@0.2.7-next.0 - - @backstage/plugin-auth-backend@0.17.5-next.0 - - @backstage/plugin-badges-backend@0.1.36-next.0 - @backstage/plugin-catalog-backend@1.7.2-next.0 - - @backstage/plugin-catalog-node@1.3.3-next.0 - - @backstage/plugin-code-coverage-backend@0.2.8-next.0 - - @backstage/plugin-jenkins-backend@0.1.32-next.0 - - @backstage/plugin-kafka-backend@0.2.35-next.0 - - @backstage/plugin-playlist-backend@0.2.5-next.0 - - @backstage/plugin-tech-insights-backend@0.5.8-next.0 - - @backstage/plugin-todo-backend@0.1.39-next.0 - - @backstage/backend-tasks@0.4.3-next.0 - - @backstage/plugin-auth-node@0.2.11-next.0 - - @backstage/plugin-events-backend@0.2.3-next.0 - - @backstage/plugin-permission-node@0.7.5-next.0 - - @backstage/plugin-rollbar-backend@0.1.39-next.0 - - @backstage/plugin-search-backend-module-pg@0.5.3-next.0 - - @backstage/plugin-azure-devops-backend@0.3.21-next.0 - - @backstage/plugin-azure-sites-backend@0.1.4-next.0 - - @backstage/plugin-explore-backend@0.0.4-next.0 - - @backstage/plugin-graphql-backend@0.1.32-next.0 - - @backstage/plugin-permission-backend@0.5.17-next.0 - - @backstage/plugin-proxy-backend@0.2.36-next.0 - - @backstage/plugin-search-backend@1.2.3-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.0 - - @backstage/plugin-search-backend-node@1.1.3-next.0 - - @backstage/plugin-tech-insights-node@0.3.10-next.0 - - @backstage/plugin-events-node@0.2.3-next.0 -## 0.2.79 +## 0.0.7 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.10.0 - - @backstage/backend-common@0.18.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.8 - - @backstage/plugin-adr-backend@0.2.5 - - @backstage/catalog-model@1.1.5 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.1 - - @backstage/plugin-search-backend-node@1.1.1 - - @backstage/catalog-client@1.3.0 - - @backstage/plugin-explore-backend@0.0.2 - - @backstage/backend-tasks@0.4.1 - - @backstage/plugin-events-backend@0.2.1 - - @backstage/plugin-catalog-node@1.3.1 + - @backstage/backend-defaults@0.1.5 - @backstage/plugin-app-backend@0.3.40 - - @backstage/plugin-code-coverage-backend@0.2.6 - @backstage/plugin-catalog-backend@1.7.0 - - @backstage/plugin-tech-insights-backend@0.5.6 - - @backstage/plugin-kubernetes-backend@0.9.1 - - @backstage/config@1.0.6 - - @backstage/plugin-search-backend@1.2.1 - - @backstage/plugin-events-node@0.2.1 - - example-app@0.2.79 - - @backstage/integration@1.4.2 - - @backstage/plugin-auth-backend@0.17.3 - - @backstage/plugin-auth-node@0.2.9 - - @backstage/plugin-azure-devops-backend@0.3.19 - - @backstage/plugin-azure-sites-backend@0.1.2 - - @backstage/plugin-badges-backend@0.1.34 - - @backstage/plugin-graphql-backend@0.1.30 - - @backstage/plugin-jenkins-backend@0.1.30 - - @backstage/plugin-kafka-backend@0.2.33 - - @backstage/plugin-permission-backend@0.5.15 - - @backstage/plugin-permission-common@0.7.3 - - @backstage/plugin-permission-node@0.7.3 - - @backstage/plugin-playlist-backend@0.2.3 - - @backstage/plugin-proxy-backend@0.2.34 - - @backstage/plugin-rollbar-backend@0.1.37 - - @backstage/plugin-search-backend-module-pg@0.5.1 - - @backstage/plugin-search-common@1.2.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.24 - - @backstage/plugin-tech-insights-node@0.3.8 - - @backstage/plugin-techdocs-backend@1.5.1 - - @backstage/plugin-todo-backend@0.1.37 -## 0.2.79-next.2 +## 0.0.7-next.2 ### Patch Changes - Updated dependencies - - @backstage/plugin-adr-backend@0.2.5-next.2 - - @backstage/backend-common@0.18.0-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.8-next.2 + - @backstage/backend-defaults@0.1.5-next.1 - @backstage/plugin-scaffolder-backend@1.10.0-next.2 - - @backstage/backend-tasks@0.4.1-next.1 - - @backstage/catalog-client@1.3.0-next.2 - @backstage/plugin-catalog-backend@1.7.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.1-next.2 - - @backstage/plugin-events-backend@0.2.1-next.1 - @backstage/plugin-app-backend@0.3.40-next.1 - - @backstage/plugin-kubernetes-backend@0.9.1-next.2 - - @backstage/plugin-catalog-node@1.3.1-next.2 - - @backstage/plugin-events-node@0.2.1-next.1 - - @backstage/plugin-auth-backend@0.17.3-next.2 - - @backstage/plugin-auth-node@0.2.9-next.1 - - @backstage/plugin-permission-node@0.7.3-next.1 - - @backstage/plugin-playlist-backend@0.2.3-next.2 - - @backstage/plugin-rollbar-backend@0.1.37-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.1-next.2 - - @backstage/plugin-tech-insights-backend@0.5.6-next.2 - - @backstage/plugin-techdocs-backend@1.5.1-next.2 - - example-app@0.2.79-next.2 - - @backstage/plugin-azure-devops-backend@0.3.19-next.1 - - @backstage/plugin-azure-sites-backend@0.1.2-next.1 - - @backstage/plugin-badges-backend@0.1.34-next.2 - - @backstage/plugin-code-coverage-backend@0.2.6-next.2 - - @backstage/plugin-explore-backend@0.0.2-next.2 - - @backstage/plugin-graphql-backend@0.1.30-next.2 - - @backstage/plugin-jenkins-backend@0.1.30-next.2 - - @backstage/plugin-kafka-backend@0.2.33-next.2 - - @backstage/plugin-permission-backend@0.5.15-next.1 - - @backstage/plugin-proxy-backend@0.2.34-next.1 - - @backstage/plugin-search-backend@1.2.1-next.2 - - @backstage/plugin-search-backend-node@1.1.1-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.24-next.1 - - @backstage/plugin-tech-insights-node@0.3.8-next.1 - - @backstage/plugin-todo-backend@0.1.37-next.2 - - @backstage/catalog-model@1.1.5-next.1 - - @backstage/config@1.0.6-next.0 - - @backstage/integration@1.4.2-next.0 - - @backstage/plugin-permission-common@0.7.3-next.0 - - @backstage/plugin-search-common@1.2.1-next.0 -## 0.2.79-next.1 +## 0.0.7-next.1 ### Patch Changes - Updated dependencies + - @backstage/backend-defaults@0.1.5-next.0 - @backstage/plugin-scaffolder-backend@1.10.0-next.1 - - @backstage/backend-common@0.18.0-next.0 - - @backstage/plugin-explore-backend@0.0.2-next.1 - - @backstage/plugin-events-backend@0.2.1-next.0 - @backstage/plugin-app-backend@0.3.40-next.0 - - @backstage/plugin-tech-insights-backend@0.5.6-next.1 - - @backstage/config@1.0.6-next.0 - @backstage/plugin-catalog-backend@1.7.0-next.1 - - @backstage/plugin-catalog-node@1.3.1-next.1 - - @backstage/plugin-events-node@0.2.1-next.0 - - example-app@0.2.79-next.1 - - @backstage/backend-tasks@0.4.1-next.0 - - @backstage/catalog-client@1.3.0-next.1 - - @backstage/catalog-model@1.1.5-next.1 - - @backstage/integration@1.4.2-next.0 - - @backstage/plugin-auth-backend@0.17.3-next.1 - - @backstage/plugin-auth-node@0.2.9-next.0 - - @backstage/plugin-azure-devops-backend@0.3.19-next.0 - - @backstage/plugin-azure-sites-backend@0.1.2-next.0 - - @backstage/plugin-badges-backend@0.1.34-next.1 - - @backstage/plugin-code-coverage-backend@0.2.6-next.1 - - @backstage/plugin-graphql-backend@0.1.30-next.1 - - @backstage/plugin-jenkins-backend@0.1.30-next.1 - - @backstage/plugin-kafka-backend@0.2.33-next.1 - - @backstage/plugin-kubernetes-backend@0.9.1-next.1 - - @backstage/plugin-permission-backend@0.5.15-next.0 - - @backstage/plugin-permission-common@0.7.3-next.0 - - @backstage/plugin-permission-node@0.7.3-next.0 - - @backstage/plugin-playlist-backend@0.2.3-next.1 - - @backstage/plugin-proxy-backend@0.2.34-next.0 - - @backstage/plugin-rollbar-backend@0.1.37-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.8-next.1 - - @backstage/plugin-search-backend@1.2.1-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.1-next.1 - - @backstage/plugin-search-backend-module-pg@0.5.1-next.1 - - @backstage/plugin-search-backend-node@1.1.1-next.1 - - @backstage/plugin-search-common@1.2.1-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.24-next.0 - - @backstage/plugin-tech-insights-node@0.3.8-next.0 - - @backstage/plugin-techdocs-backend@1.5.1-next.1 - - @backstage/plugin-todo-backend@0.1.37-next.1 -## 0.2.79-next.0 +## 0.0.7-next.0 ### Patch Changes - Updated dependencies - - @backstage/catalog-model@1.1.5-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.1-next.0 - - @backstage/plugin-search-backend-node@1.1.1-next.0 - - @backstage/catalog-client@1.3.0-next.0 - - @backstage/plugin-explore-backend@0.0.2-next.0 - - @backstage/plugin-code-coverage-backend@0.2.6-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.8-next.0 - @backstage/plugin-scaffolder-backend@1.9.1-next.0 - @backstage/plugin-catalog-backend@1.7.0-next.0 - - @backstage/plugin-search-backend@1.2.1-next.0 - - example-app@0.2.79-next.0 - - @backstage/backend-common@0.17.0 - - @backstage/backend-tasks@0.4.0 - - @backstage/config@1.0.5 - - @backstage/integration@1.4.1 + - @backstage/backend-defaults@0.1.4 - @backstage/plugin-app-backend@0.3.39 - - @backstage/plugin-auth-backend@0.17.3-next.0 - - @backstage/plugin-auth-node@0.2.8 - - @backstage/plugin-azure-devops-backend@0.3.18 - - @backstage/plugin-azure-sites-backend@0.1.1 - - @backstage/plugin-badges-backend@0.1.34-next.0 - - @backstage/plugin-catalog-node@1.3.1-next.0 - - @backstage/plugin-events-backend@0.2.0 - - @backstage/plugin-events-node@0.2.0 - - @backstage/plugin-graphql-backend@0.1.30-next.0 - - @backstage/plugin-jenkins-backend@0.1.30-next.0 - - @backstage/plugin-kafka-backend@0.2.33-next.0 - - @backstage/plugin-kubernetes-backend@0.9.1-next.0 - - @backstage/plugin-permission-backend@0.5.14 - - @backstage/plugin-permission-common@0.7.2 - - @backstage/plugin-permission-node@0.7.2 - - @backstage/plugin-playlist-backend@0.2.3-next.0 - - @backstage/plugin-proxy-backend@0.2.33 - - @backstage/plugin-rollbar-backend@0.1.36 - - @backstage/plugin-search-backend-module-pg@0.5.1-next.0 - - @backstage/plugin-search-common@1.2.0 - - @backstage/plugin-tech-insights-backend@0.5.6-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23 - - @backstage/plugin-tech-insights-node@0.3.7 - - @backstage/plugin-techdocs-backend@1.5.1-next.0 - - @backstage/plugin-todo-backend@0.1.37-next.0 -## 0.2.78 +## 0.0.6 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.9.0 - - @backstage/plugin-azure-devops-backend@0.3.18 - - @backstage/plugin-kubernetes-backend@0.9.0 - @backstage/plugin-catalog-backend@1.6.0 - - @backstage/catalog-client@1.2.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.7 - - @backstage/plugin-search-backend@1.2.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.0 - - @backstage/plugin-search-backend-node@1.1.0 - - @backstage/plugin-playlist-backend@0.2.2 - - @backstage/plugin-search-backend-module-pg@0.5.0 - - @backstage/backend-common@0.17.0 - @backstage/plugin-app-backend@0.3.39 - - @backstage/plugin-catalog-node@1.3.0 - - @backstage/plugin-events-backend@0.2.0 - - @backstage/backend-tasks@0.4.0 - - @backstage/plugin-permission-backend@0.5.14 - - @backstage/plugin-permission-common@0.7.2 - - @backstage/plugin-permission-node@0.7.2 - - @backstage/plugin-kafka-backend@0.2.32 - - @backstage/plugin-jenkins-backend@0.1.29 - - @backstage/plugin-events-node@0.2.0 - - @backstage/integration@1.4.1 - - @backstage/plugin-auth-backend@0.17.2 - - @backstage/plugin-auth-node@0.2.8 - - @backstage/plugin-azure-sites-backend@0.1.1 - - @backstage/plugin-code-coverage-backend@0.2.5 - - @backstage/plugin-graphql-backend@0.1.29 - - @backstage/plugin-proxy-backend@0.2.33 - - @backstage/plugin-rollbar-backend@0.1.36 - - @backstage/plugin-techdocs-backend@1.5.0 - - @backstage/plugin-todo-backend@0.1.36 - - @backstage/plugin-explore-backend@0.0.1 - - @backstage/plugin-search-common@1.2.0 - - example-app@0.2.78 - - @backstage/plugin-badges-backend@0.1.33 - - @backstage/plugin-tech-insights-backend@0.5.5 - - @backstage/catalog-model@1.1.4 - - @backstage/config@1.0.5 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23 - - @backstage/plugin-tech-insights-node@0.3.7 + - @backstage/backend-defaults@0.1.4 -## 0.2.78-next.4 +## 0.0.6-next.3 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.6.0-next.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.3 - @backstage/plugin-scaffolder-backend@1.9.0-next.3 - - @backstage/backend-tasks@0.4.0-next.3 - - @backstage/plugin-permission-backend@0.5.14-next.3 - - @backstage/plugin-permission-common@0.7.2-next.2 - - @backstage/plugin-permission-node@0.7.2-next.3 - - @backstage/plugin-playlist-backend@0.2.2-next.4 - - @backstage/plugin-search-backend@1.2.0-next.3 - - @backstage/plugin-kubernetes-backend@0.8.1-next.4 - - @backstage/backend-common@0.17.0-next.3 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.0-next.3 - - @backstage/plugin-techdocs-backend@1.5.0-next.3 - - example-app@0.2.78-next.4 - - @backstage/catalog-client@1.2.0-next.1 - - @backstage/catalog-model@1.1.4-next.1 - - @backstage/config@1.0.5-next.1 - - @backstage/integration@1.4.1-next.1 + - @backstage/backend-defaults@0.1.4-next.3 - @backstage/plugin-app-backend@0.3.39-next.3 - - @backstage/plugin-auth-backend@0.17.2-next.3 - - @backstage/plugin-auth-node@0.2.8-next.3 - - @backstage/plugin-azure-devops-backend@0.3.18-next.3 - - @backstage/plugin-azure-sites-backend@0.1.1-next.3 - - @backstage/plugin-badges-backend@0.1.33-next.3 - - @backstage/plugin-catalog-node@1.3.0-next.3 - - @backstage/plugin-code-coverage-backend@0.2.5-next.3 - - @backstage/plugin-events-backend@0.2.0-next.3 - - @backstage/plugin-events-node@0.2.0-next.3 - - @backstage/plugin-explore-backend@0.0.1-next.2 - - @backstage/plugin-graphql-backend@0.1.29-next.3 - - @backstage/plugin-jenkins-backend@0.1.29-next.3 - - @backstage/plugin-kafka-backend@0.2.32-next.3 - - @backstage/plugin-proxy-backend@0.2.33-next.3 - - @backstage/plugin-rollbar-backend@0.1.36-next.3 - - @backstage/plugin-search-backend-module-pg@0.4.3-next.3 - - @backstage/plugin-search-backend-node@1.1.0-next.3 - - @backstage/plugin-search-common@1.2.0-next.3 - - @backstage/plugin-tech-insights-backend@0.5.5-next.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.3 - - @backstage/plugin-tech-insights-node@0.3.7-next.3 - - @backstage/plugin-todo-backend@0.1.36-next.3 -## 0.2.78-next.3 +## 0.0.6-next.2 ### Patch Changes - Updated dependencies - - example-app@0.2.78-next.3 - - @backstage/backend-common@0.17.0-next.2 - - @backstage/backend-tasks@0.4.0-next.2 - - @backstage/catalog-client@1.2.0-next.1 - - @backstage/catalog-model@1.1.4-next.1 - - @backstage/config@1.0.5-next.1 - - @backstage/integration@1.4.1-next.1 - - @backstage/plugin-app-backend@0.3.39-next.2 - - @backstage/plugin-auth-backend@0.17.2-next.2 - - @backstage/plugin-auth-node@0.2.8-next.2 - - @backstage/plugin-azure-devops-backend@0.3.18-next.2 - - @backstage/plugin-azure-sites-backend@0.1.1-next.2 - - @backstage/plugin-badges-backend@0.1.33-next.2 - @backstage/plugin-catalog-backend@1.6.0-next.2 - - @backstage/plugin-catalog-node@1.3.0-next.2 - - @backstage/plugin-code-coverage-backend@0.2.5-next.2 - - @backstage/plugin-events-backend@0.2.0-next.2 - - @backstage/plugin-events-node@0.2.0-next.2 - - @backstage/plugin-explore-backend@0.0.1-next.1 - - @backstage/plugin-graphql-backend@0.1.29-next.2 - - @backstage/plugin-jenkins-backend@0.1.29-next.2 - - @backstage/plugin-kafka-backend@0.2.32-next.2 - - @backstage/plugin-kubernetes-backend@0.8.1-next.3 - - @backstage/plugin-permission-backend@0.5.14-next.2 - - @backstage/plugin-permission-common@0.7.2-next.1 - - @backstage/plugin-permission-node@0.7.2-next.2 - - @backstage/plugin-playlist-backend@0.2.2-next.3 - - @backstage/plugin-proxy-backend@0.2.33-next.2 - - @backstage/plugin-rollbar-backend@0.1.36-next.2 - - @backstage/plugin-scaffolder-backend@1.9.0-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.2 - - @backstage/plugin-search-backend@1.2.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.0-next.2 - - @backstage/plugin-search-backend-module-pg@0.4.3-next.2 - - @backstage/plugin-search-backend-node@1.1.0-next.2 - - @backstage/plugin-search-common@1.2.0-next.2 - - @backstage/plugin-tech-insights-backend@0.5.5-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.2 - - @backstage/plugin-tech-insights-node@0.3.7-next.2 - - @backstage/plugin-techdocs-backend@1.4.2-next.2 - - @backstage/plugin-todo-backend@0.1.36-next.2 - -## 0.2.78-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-azure-devops-backend@0.3.18-next.2 - - @backstage/plugin-search-backend@1.2.0-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.1.0-next.2 - - @backstage/plugin-search-backend-node@1.1.0-next.2 - - @backstage/plugin-catalog-backend@1.6.0-next.2 - - @backstage/plugin-playlist-backend@0.2.2-next.2 - - @backstage/plugin-search-backend-module-pg@0.4.3-next.2 - @backstage/plugin-app-backend@0.3.39-next.2 - - @backstage/plugin-catalog-node@1.3.0-next.2 - - @backstage/plugin-events-backend@0.2.0-next.2 - @backstage/plugin-scaffolder-backend@1.9.0-next.2 - - @backstage/backend-common@0.17.0-next.2 - - @backstage/plugin-search-common@1.2.0-next.2 - - example-app@0.2.78-next.2 - - @backstage/plugin-techdocs-backend@1.4.2-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.2 - - @backstage/backend-tasks@0.4.0-next.2 - - @backstage/plugin-auth-backend@0.17.2-next.2 - - @backstage/plugin-auth-node@0.2.8-next.2 - - @backstage/plugin-azure-sites-backend@0.1.1-next.2 - - @backstage/plugin-badges-backend@0.1.33-next.2 - - @backstage/plugin-code-coverage-backend@0.2.5-next.2 - - @backstage/plugin-explore-backend@0.0.1-next.1 - - @backstage/plugin-graphql-backend@0.1.29-next.2 - - @backstage/plugin-jenkins-backend@0.1.29-next.2 - - @backstage/plugin-kafka-backend@0.2.32-next.2 - - @backstage/plugin-kubernetes-backend@0.8.1-next.2 - - @backstage/plugin-permission-backend@0.5.14-next.2 - - @backstage/plugin-permission-node@0.7.2-next.2 - - @backstage/plugin-proxy-backend@0.2.33-next.2 - - @backstage/plugin-rollbar-backend@0.1.36-next.2 - - @backstage/plugin-tech-insights-backend@0.5.5-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.2 - - @backstage/plugin-tech-insights-node@0.3.7-next.2 - - @backstage/plugin-todo-backend@0.1.36-next.2 - - @backstage/catalog-client@1.2.0-next.1 - - @backstage/catalog-model@1.1.4-next.1 - - @backstage/config@1.0.5-next.1 - - @backstage/integration@1.4.1-next.1 - - @backstage/plugin-events-node@0.2.0-next.2 - - @backstage/plugin-permission-common@0.7.2-next.1 + - @backstage/backend-defaults@0.1.4-next.2 -## 0.2.78-next.1 +## 0.0.6-next.1 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.17.0-next.1 - @backstage/plugin-catalog-backend@1.6.0-next.1 - - @backstage/plugin-kafka-backend@0.2.32-next.1 - - @backstage/backend-tasks@0.4.0-next.1 - - @backstage/plugin-search-backend-node@1.0.5-next.1 - - @backstage/plugin-jenkins-backend@0.1.29-next.1 - @backstage/plugin-scaffolder-backend@1.8.1-next.1 - - @backstage/plugin-explore-backend@0.0.1-next.0 - - @backstage/plugin-proxy-backend@0.2.33-next.1 - @backstage/plugin-app-backend@0.3.39-next.1 - - @backstage/plugin-auth-backend@0.17.2-next.1 - - @backstage/plugin-auth-node@0.2.8-next.1 - - @backstage/plugin-azure-devops-backend@0.3.18-next.1 - - @backstage/plugin-azure-sites-backend@0.1.1-next.1 - - @backstage/plugin-badges-backend@0.1.33-next.1 - - @backstage/plugin-catalog-node@1.2.2-next.1 - - @backstage/plugin-code-coverage-backend@0.2.5-next.1 - - @backstage/plugin-events-backend@0.2.0-next.1 - - @backstage/plugin-graphql-backend@0.1.29-next.1 - - @backstage/plugin-kubernetes-backend@0.8.1-next.1 - - @backstage/plugin-permission-backend@0.5.14-next.1 - - @backstage/plugin-permission-node@0.7.2-next.1 - - @backstage/plugin-playlist-backend@0.2.2-next.1 - - @backstage/plugin-rollbar-backend@0.1.36-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.1 - - @backstage/plugin-search-backend@1.1.2-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.5-next.1 - - @backstage/plugin-search-backend-module-pg@0.4.3-next.1 - - @backstage/plugin-tech-insights-backend@0.5.5-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.1 - - @backstage/plugin-tech-insights-node@0.3.7-next.1 - - @backstage/plugin-techdocs-backend@1.4.2-next.1 - - @backstage/plugin-todo-backend@0.1.36-next.1 - - example-app@0.2.78-next.1 - - @backstage/config@1.0.5-next.1 - - @backstage/integration@1.4.1-next.1 - - @backstage/catalog-client@1.2.0-next.1 - - @backstage/catalog-model@1.1.4-next.1 - - @backstage/plugin-events-node@0.2.0-next.1 - - @backstage/plugin-permission-common@0.7.2-next.1 - - @backstage/plugin-search-common@1.1.2-next.1 + - @backstage/backend-defaults@0.1.4-next.1 -## 0.2.78-next.0 +## 0.0.6-next.0 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.8.1-next.0 - - @backstage/catalog-client@1.2.0-next.0 - @backstage/plugin-catalog-backend@1.6.0-next.0 - - @backstage/plugin-events-backend@0.2.0-next.0 - - @backstage/plugin-search-backend-node@1.0.5-next.0 - - @backstage/plugin-events-node@0.2.0-next.0 - - @backstage/backend-common@0.16.1-next.0 - - @backstage/integration@1.4.1-next.0 - @backstage/plugin-app-backend@0.3.39-next.0 - - @backstage/plugin-auth-backend@0.17.2-next.0 - - @backstage/plugin-auth-node@0.2.8-next.0 - - @backstage/plugin-azure-devops-backend@0.3.18-next.0 - - @backstage/plugin-azure-sites-backend@0.1.1-next.0 - - @backstage/plugin-code-coverage-backend@0.2.5-next.0 - - @backstage/plugin-graphql-backend@0.1.29-next.0 - - @backstage/plugin-jenkins-backend@0.1.29-next.0 - - @backstage/plugin-permission-backend@0.5.14-next.0 - - @backstage/plugin-permission-common@0.7.2-next.0 - - @backstage/plugin-permission-node@0.7.2-next.0 - - @backstage/plugin-playlist-backend@0.2.2-next.0 - - @backstage/plugin-proxy-backend@0.2.33-next.0 - - @backstage/plugin-rollbar-backend@0.1.36-next.0 - - @backstage/plugin-techdocs-backend@1.4.2-next.0 - - @backstage/plugin-todo-backend@0.1.36-next.0 - - @backstage/plugin-kubernetes-backend@0.8.1-next.0 - - example-app@0.2.78-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.7-next.0 - - @backstage/plugin-badges-backend@0.1.33-next.0 - - @backstage/plugin-catalog-node@1.2.2-next.0 - - @backstage/plugin-tech-insights-backend@0.5.5-next.0 - - @backstage/backend-tasks@0.3.8-next.0 - - @backstage/catalog-model@1.1.4-next.0 - - @backstage/config@1.0.5-next.0 - - @backstage/plugin-kafka-backend@0.2.32-next.0 - - @backstage/plugin-search-backend@1.1.2-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.5-next.0 - - @backstage/plugin-search-backend-module-pg@0.4.3-next.0 - - @backstage/plugin-search-common@1.1.2-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.23-next.0 - - @backstage/plugin-tech-insights-node@0.3.7-next.0 + - @backstage/backend-defaults@0.1.4-next.0 -## 0.2.77 +## 0.0.5 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.16.0 - - @backstage/plugin-auth-backend@0.17.1 - @backstage/plugin-catalog-backend@1.5.1 - - @backstage/plugin-techdocs-backend@1.4.1 - @backstage/plugin-scaffolder-backend@1.8.0 - - @backstage/integration@1.4.0 - - @backstage/backend-tasks@0.3.7 - - @backstage/plugin-playlist-backend@0.2.1 - - @backstage/plugin-azure-devops-backend@0.3.17 - - @backstage/catalog-model@1.1.3 - - @backstage/plugin-auth-node@0.2.7 - - @backstage/plugin-permission-common@0.7.1 - - @backstage/plugin-code-coverage-backend@0.2.4 - - @backstage/plugin-events-backend@0.1.0 - - @backstage/plugin-events-node@0.1.0 - - @backstage/plugin-kubernetes-backend@0.8.0 - - @backstage/plugin-tech-insights-backend@0.5.4 - - @backstage/plugin-tech-insights-node@0.3.6 - - @backstage/plugin-azure-sites-backend@0.1.0 - - example-app@0.2.77 - @backstage/plugin-app-backend@0.3.38 - - @backstage/plugin-badges-backend@0.1.32 - - @backstage/plugin-catalog-node@1.2.1 - - @backstage/plugin-graphql-backend@0.1.28 - - @backstage/plugin-jenkins-backend@0.1.28 - - @backstage/plugin-kafka-backend@0.2.31 - - @backstage/plugin-permission-backend@0.5.13 - - @backstage/plugin-permission-node@0.7.1 - - @backstage/plugin-proxy-backend@0.2.32 - - @backstage/plugin-rollbar-backend@0.1.35 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.6 - - @backstage/plugin-search-backend@1.1.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.4 - - @backstage/plugin-search-backend-module-pg@0.4.2 - - @backstage/plugin-search-backend-node@1.0.4 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22 - - @backstage/plugin-todo-backend@0.1.35 - - @backstage/catalog-client@1.1.2 - - @backstage/config@1.0.4 - - @backstage/plugin-search-common@1.1.1 + - @backstage/backend-defaults@0.1.3 -## 0.2.77-next.2 +## 0.0.5-next.2 ### Patch Changes - Updated dependencies - - @backstage/plugin-auth-backend@0.17.1-next.1 - - @backstage/backend-common@0.16.0-next.1 - @backstage/plugin-scaffolder-backend@1.8.0-next.2 - - @backstage/plugin-code-coverage-backend@0.2.4-next.1 - - @backstage/plugin-kubernetes-backend@0.8.0-next.1 - - @backstage/plugin-tech-insights-backend@0.5.4-next.1 - - example-app@0.2.77-next.2 - - @backstage/backend-tasks@0.3.7-next.1 - @backstage/plugin-app-backend@0.3.38-next.1 - - @backstage/plugin-auth-node@0.2.7-next.1 - - @backstage/plugin-azure-devops-backend@0.3.17-next.2 - - @backstage/plugin-azure-sites-backend@0.1.0-next.1 - - @backstage/plugin-badges-backend@0.1.32-next.1 - @backstage/plugin-catalog-backend@1.5.1-next.1 - - @backstage/plugin-graphql-backend@0.1.28-next.1 - - @backstage/plugin-jenkins-backend@0.1.28-next.1 - - @backstage/plugin-kafka-backend@0.2.31-next.1 - - @backstage/plugin-permission-backend@0.5.13-next.1 - - @backstage/plugin-permission-node@0.7.1-next.1 - - @backstage/plugin-playlist-backend@0.2.1-next.2 - - @backstage/plugin-proxy-backend@0.2.32-next.1 - - @backstage/plugin-rollbar-backend@0.1.35-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.2 - - @backstage/plugin-search-backend@1.1.1-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.1 - - @backstage/plugin-search-backend-module-pg@0.4.2-next.1 - - @backstage/plugin-search-backend-node@1.0.4-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.1 - - @backstage/plugin-tech-insights-node@0.3.6-next.1 - - @backstage/plugin-techdocs-backend@1.4.1-next.1 - - @backstage/plugin-todo-backend@0.1.35-next.1 - - @backstage/catalog-client@1.1.2-next.0 - - @backstage/catalog-model@1.1.3-next.0 - - @backstage/config@1.0.4-next.0 - - @backstage/integration@1.4.0-next.0 - - @backstage/plugin-permission-common@0.7.1-next.0 - - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/backend-defaults@0.1.3-next.1 -## 0.2.77-next.1 +## 0.0.5-next.1 ### Patch Changes - Updated dependencies - @backstage/plugin-scaffolder-backend@1.8.0-next.1 - - @backstage/plugin-playlist-backend@0.2.1-next.1 - - @backstage/plugin-azure-devops-backend@0.3.17-next.1 - - example-app@0.2.77-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.1 -## 0.2.77-next.0 +## 0.0.5-next.0 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.16.0-next.0 - @backstage/plugin-catalog-backend@1.5.1-next.0 - - @backstage/plugin-techdocs-backend@1.4.1-next.0 - @backstage/plugin-scaffolder-backend@1.8.0-next.0 - - @backstage/integration@1.4.0-next.0 - - @backstage/plugin-auth-backend@0.17.1-next.0 - - @backstage/backend-tasks@0.3.7-next.0 - - @backstage/catalog-model@1.1.3-next.0 - - @backstage/plugin-auth-node@0.2.7-next.0 - - @backstage/plugin-permission-common@0.7.1-next.0 - - @backstage/plugin-tech-insights-backend@0.5.4-next.0 - - @backstage/plugin-tech-insights-node@0.3.6-next.0 - - @backstage/plugin-azure-sites-backend@0.1.0-next.0 - - @backstage/plugin-kubernetes-backend@0.8.0-next.0 - - example-app@0.2.77-next.0 - @backstage/plugin-app-backend@0.3.38-next.0 - - @backstage/plugin-azure-devops-backend@0.3.17-next.0 - - @backstage/plugin-badges-backend@0.1.32-next.0 - - @backstage/plugin-code-coverage-backend@0.2.4-next.0 - - @backstage/plugin-graphql-backend@0.1.28-next.0 - - @backstage/plugin-jenkins-backend@0.1.28-next.0 - - @backstage/plugin-kafka-backend@0.2.31-next.0 - - @backstage/plugin-permission-backend@0.5.13-next.0 - - @backstage/plugin-permission-node@0.7.1-next.0 - - @backstage/plugin-playlist-backend@0.2.1-next.0 - - @backstage/plugin-proxy-backend@0.2.32-next.0 - - @backstage/plugin-rollbar-backend@0.1.35-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.0 - - @backstage/plugin-search-backend@1.1.1-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.0 - - @backstage/plugin-search-backend-module-pg@0.4.2-next.0 - - @backstage/plugin-search-backend-node@1.0.4-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.0 - - @backstage/plugin-todo-backend@0.1.35-next.0 - - @backstage/catalog-client@1.1.2-next.0 - - @backstage/config@1.0.4-next.0 - - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/backend-defaults@0.1.3-next.0 -## 0.2.76 +## 0.0.4 ### Patch Changes - Updated dependencies - - @backstage/catalog-model@1.1.2 - - @backstage/backend-common@0.15.2 - @backstage/plugin-catalog-backend@1.5.0 - @backstage/plugin-scaffolder-backend@1.7.0 - - @backstage/plugin-auth-node@0.2.6 - - @backstage/backend-tasks@0.3.6 - - @backstage/plugin-permission-node@0.7.0 - - @backstage/plugin-auth-backend@0.17.0 - - @backstage/plugin-permission-common@0.7.0 - - @backstage/plugin-tech-insights-backend@0.5.3 - - @backstage/plugin-search-backend@1.1.0 - - @backstage/catalog-client@1.1.1 - - @backstage/plugin-playlist-backend@0.2.0 - - @backstage/plugin-jenkins-backend@0.1.27 + - @backstage/backend-defaults@0.1.2 - @backstage/plugin-app-backend@0.3.37 - - @backstage/plugin-badges-backend@0.1.31 - - @backstage/plugin-graphql-backend@0.1.27 - - @backstage/plugin-permission-backend@0.5.12 - - @backstage/plugin-rollbar-backend@0.1.34 - - @backstage/plugin-kubernetes-backend@0.7.3 - - @backstage/plugin-search-common@1.1.0 - - @backstage/plugin-search-backend-node@1.0.3 - - @backstage/plugin-search-backend-module-pg@0.4.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.3 - - @backstage/plugin-techdocs-backend@1.4.0 - - @backstage/plugin-tech-insights-node@0.3.5 - - example-app@0.2.76 - - @backstage/plugin-code-coverage-backend@0.2.3 - - @backstage/plugin-kafka-backend@0.2.30 - - @backstage/plugin-todo-backend@0.1.34 - - @backstage/plugin-azure-devops-backend@0.3.16 - - @backstage/plugin-proxy-backend@0.2.31 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.5 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21 - - @backstage/config@1.0.3 - - @backstage/integration@1.3.2 -## 0.2.76-next.2 +## 0.0.4-next.2 ### Patch Changes - Updated dependencies - @backstage/plugin-catalog-backend@1.5.0-next.2 - - @backstage/backend-tasks@0.3.6-next.2 - - @backstage/backend-common@0.15.2-next.2 - - @backstage/plugin-permission-common@0.7.0-next.2 - - @backstage/plugin-permission-node@0.7.0-next.2 - @backstage/plugin-scaffolder-backend@1.7.0-next.2 - - @backstage/plugin-playlist-backend@0.2.0-next.2 - - @backstage/plugin-badges-backend@0.1.31-next.2 - - @backstage/plugin-graphql-backend@0.1.27-next.2 - - @backstage/plugin-permission-backend@0.5.12-next.2 - - @backstage/plugin-rollbar-backend@0.1.34-next.2 - - @backstage/plugin-search-backend@1.1.0-next.2 - - @backstage/plugin-tech-insights-backend@0.5.3-next.2 - - @backstage/plugin-techdocs-backend@1.4.0-next.2 - - example-app@0.2.76-next.2 - - @backstage/plugin-search-backend-node@1.0.3-next.2 - - @backstage/plugin-tech-insights-node@0.3.5-next.2 - @backstage/plugin-app-backend@0.3.37-next.2 - - @backstage/plugin-auth-backend@0.17.0-next.2 - - @backstage/plugin-auth-node@0.2.6-next.2 - - @backstage/plugin-azure-devops-backend@0.3.16-next.2 - - @backstage/plugin-code-coverage-backend@0.2.3-next.2 - - @backstage/plugin-jenkins-backend@0.1.27-next.2 - - @backstage/plugin-kafka-backend@0.2.30-next.2 - - @backstage/plugin-kubernetes-backend@0.7.3-next.2 - - @backstage/plugin-proxy-backend@0.2.31-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.2 - - @backstage/plugin-search-backend-module-pg@0.4.1-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.2 - - @backstage/plugin-todo-backend@0.1.34-next.2 - - @backstage/plugin-search-common@1.1.0-next.2 - - @backstage/catalog-client@1.1.1-next.2 - - @backstage/catalog-model@1.1.2-next.2 - - @backstage/config@1.0.3-next.2 - - @backstage/integration@1.3.2-next.2 + - @backstage/backend-defaults@0.1.2-next.2 -## 0.2.76-next.1 +## 0.0.4-next.1 ### Patch Changes - Updated dependencies - - @backstage/plugin-auth-backend@0.17.0-next.1 - - @backstage/plugin-search-backend@1.1.0-next.1 - - @backstage/catalog-client@1.1.1-next.1 - - @backstage/backend-common@0.15.2-next.1 - @backstage/plugin-scaffolder-backend@1.7.0-next.1 - - @backstage/plugin-search-common@1.1.0-next.1 - - @backstage/plugin-search-backend-node@1.0.3-next.1 - - @backstage/plugin-search-backend-module-pg@0.4.1-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.1 - - @backstage/plugin-kubernetes-backend@0.7.3-next.1 - - @backstage/plugin-tech-insights-backend@0.5.3-next.1 - - example-app@0.2.76-next.1 - - @backstage/backend-tasks@0.3.6-next.1 - - @backstage/catalog-model@1.1.2-next.1 - - @backstage/config@1.0.3-next.1 - - @backstage/integration@1.3.2-next.1 + - @backstage/backend-defaults@0.1.2-next.1 - @backstage/plugin-app-backend@0.3.37-next.1 - - @backstage/plugin-auth-node@0.2.6-next.1 - - @backstage/plugin-azure-devops-backend@0.3.16-next.1 - - @backstage/plugin-badges-backend@0.1.31-next.1 - @backstage/plugin-catalog-backend@1.4.1-next.1 - - @backstage/plugin-code-coverage-backend@0.2.3-next.1 - - @backstage/plugin-graphql-backend@0.1.27-next.1 - - @backstage/plugin-jenkins-backend@0.1.27-next.1 - - @backstage/plugin-kafka-backend@0.2.30-next.1 - - @backstage/plugin-permission-backend@0.5.12-next.1 - - @backstage/plugin-permission-common@0.6.5-next.1 - - @backstage/plugin-permission-node@0.6.6-next.1 - - @backstage/plugin-playlist-backend@0.1.1-next.1 - - @backstage/plugin-proxy-backend@0.2.31-next.1 - - @backstage/plugin-rollbar-backend@0.1.34-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.1 - - @backstage/plugin-tech-insights-node@0.3.5-next.1 - - @backstage/plugin-techdocs-backend@1.3.1-next.1 - - @backstage/plugin-todo-backend@0.1.34-next.1 -## 0.2.76-next.0 +## 0.0.4-next.0 ### Patch Changes - Updated dependencies - - @backstage/catalog-model@1.1.2-next.0 - @backstage/plugin-scaffolder-backend@1.7.0-next.0 - - @backstage/plugin-auth-backend@0.17.0-next.0 + - @backstage/backend-defaults@0.1.2-next.0 - @backstage/plugin-catalog-backend@1.4.1-next.0 - - @backstage/plugin-jenkins-backend@0.1.27-next.0 - @backstage/plugin-app-backend@0.3.37-next.0 - - @backstage/plugin-tech-insights-node@0.3.5-next.0 - - example-app@0.2.76-next.0 - - @backstage/catalog-client@1.1.1-next.0 - - @backstage/plugin-badges-backend@0.1.31-next.0 - - @backstage/plugin-code-coverage-backend@0.2.3-next.0 - - @backstage/plugin-kafka-backend@0.2.30-next.0 - - @backstage/plugin-kubernetes-backend@0.7.3-next.0 - - @backstage/plugin-playlist-backend@0.1.1-next.0 - - @backstage/plugin-tech-insights-backend@0.5.3-next.0 - - @backstage/plugin-techdocs-backend@1.3.1-next.0 - - @backstage/plugin-todo-backend@0.1.34-next.0 - - @backstage/backend-common@0.15.2-next.0 - - @backstage/backend-tasks@0.3.6-next.0 - - @backstage/plugin-auth-node@0.2.6-next.0 - - @backstage/plugin-permission-node@0.6.6-next.0 - - @backstage/plugin-rollbar-backend@0.1.34-next.0 - - @backstage/plugin-search-backend-module-pg@0.4.1-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.0 - - @backstage/config@1.0.3-next.0 - - @backstage/integration@1.3.2-next.0 - - @backstage/plugin-azure-devops-backend@0.3.16-next.0 - - @backstage/plugin-graphql-backend@0.1.27-next.0 - - @backstage/plugin-permission-backend@0.5.12-next.0 - - @backstage/plugin-permission-common@0.6.5-next.0 - - @backstage/plugin-proxy-backend@0.2.31-next.0 - - @backstage/plugin-search-backend@1.0.3-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.0 - - @backstage/plugin-search-backend-node@1.0.3-next.0 - - @backstage/plugin-search-common@1.0.2-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.0 -## 0.2.75 +## 0.0.3 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.15.1 - @backstage/plugin-scaffolder-backend@1.6.0 - - @backstage/plugin-auth-node@0.2.5 - - @backstage/plugin-permission-node@0.6.5 - - @backstage/plugin-kubernetes-backend@0.7.2 - - @backstage/plugin-kafka-backend@0.2.29 - - @backstage/plugin-proxy-backend@0.2.30 - - @backstage/plugin-auth-backend@0.16.0 - - @backstage/integration@1.3.1 - @backstage/plugin-catalog-backend@1.4.0 - - @backstage/plugin-azure-devops-backend@0.3.15 - - @backstage/plugin-search-backend-node@1.0.2 - - @backstage/plugin-tech-insights-node@0.3.4 - - @backstage/backend-tasks@0.3.5 - - @backstage/plugin-techdocs-backend@1.3.0 - - @backstage/catalog-client@1.1.0 - - @backstage/catalog-model@1.1.1 - - @backstage/config@1.0.2 - - @backstage/plugin-permission-common@0.6.4 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.4 - - @backstage/plugin-search-backend-module-pg@0.4.0 - - @backstage/plugin-jenkins-backend@0.1.26 - - @backstage/plugin-playlist-backend@0.1.0 - - @backstage/plugin-app-backend@0.3.36 - - @backstage/plugin-graphql-backend@0.1.26 - - @backstage/plugin-rollbar-backend@0.1.33 - - @backstage/plugin-code-coverage-backend@0.2.2 - - @backstage/plugin-permission-backend@0.5.11 - - @backstage/plugin-todo-backend@0.1.33 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.2 - - @backstage/plugin-tech-insights-backend@0.5.2 - - @backstage/plugin-badges-backend@0.1.30 - - example-app@0.2.75 - - @backstage/plugin-search-backend@1.0.2 - - @backstage/plugin-search-common@1.0.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20 + - @backstage/backend-defaults@0.1.1 -## 0.2.75-next.3 +## 0.0.3-next.1 ### Patch Changes - Updated dependencies - - @backstage/catalog-client@1.1.0-next.2 - - @backstage/catalog-model@1.1.1-next.0 - - @backstage/config@1.0.2-next.0 - - @backstage/integration@1.3.1-next.2 - - @backstage/plugin-permission-common@0.6.4-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.4-next.1 - - @backstage/plugin-catalog-backend@1.4.0-next.3 - - @backstage/plugin-auth-backend@0.16.0-next.3 - - @backstage/backend-common@0.15.1-next.3 - - @backstage/plugin-scaffolder-backend@1.6.0-next.3 - - @backstage/plugin-badges-backend@0.1.30-next.1 - - @backstage/plugin-code-coverage-backend@0.2.2-next.2 - - @backstage/plugin-jenkins-backend@0.1.26-next.3 - - @backstage/plugin-kubernetes-backend@0.7.2-next.3 - - @backstage/plugin-tech-insights-backend@0.5.2-next.2 - - @backstage/plugin-techdocs-backend@1.3.0-next.2 - - @backstage/plugin-todo-backend@0.1.33-next.2 - - example-app@0.2.75-next.3 - - @backstage/plugin-kafka-backend@0.2.29-next.1 - - @backstage/backend-tasks@0.3.5-next.1 - - @backstage/plugin-app-backend@0.3.36-next.3 - - @backstage/plugin-auth-node@0.2.5-next.3 - - @backstage/plugin-azure-devops-backend@0.3.15-next.2 - - @backstage/plugin-graphql-backend@0.1.26-next.3 - - @backstage/plugin-permission-backend@0.5.11-next.2 - - @backstage/plugin-permission-node@0.6.5-next.3 - - @backstage/plugin-proxy-backend@0.2.30-next.2 - - @backstage/plugin-rollbar-backend@0.1.33-next.3 - - @backstage/plugin-search-backend@1.0.2-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.2-next.2 - - @backstage/plugin-search-backend-module-pg@0.4.0-next.2 - - @backstage/plugin-search-backend-node@1.0.2-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20-next.1 - - @backstage/plugin-tech-insights-node@0.3.4-next.1 - -## 0.2.75-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.7.2-next.2 - - @backstage/backend-common@0.15.1-next.2 - - @backstage/integration@1.3.1-next.1 - - @backstage/plugin-catalog-backend@1.4.0-next.2 - - @backstage/plugin-scaffolder-backend@1.6.0-next.2 - - @backstage/plugin-auth-node@0.2.5-next.2 - - @backstage/plugin-techdocs-backend@1.3.0-next.1 - - @backstage/plugin-jenkins-backend@0.1.26-next.2 - - @backstage/catalog-client@1.0.5-next.1 - - @backstage/plugin-app-backend@0.3.36-next.2 - - @backstage/plugin-auth-backend@0.16.0-next.2 - - @backstage/plugin-azure-devops-backend@0.3.15-next.1 - - @backstage/plugin-code-coverage-backend@0.2.2-next.1 - - @backstage/plugin-graphql-backend@0.1.26-next.2 - - @backstage/plugin-permission-backend@0.5.11-next.1 - - @backstage/plugin-permission-common@0.6.4-next.1 - - @backstage/plugin-permission-node@0.6.5-next.2 - - @backstage/plugin-proxy-backend@0.2.30-next.1 - - @backstage/plugin-rollbar-backend@0.1.33-next.2 - - @backstage/plugin-todo-backend@0.1.33-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.2-next.1 - - example-app@0.2.75-next.2 - -## 0.2.75-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-node@0.2.5-next.1 - - @backstage/plugin-permission-node@0.6.5-next.1 - - @backstage/backend-common@0.15.1-next.1 - @backstage/plugin-catalog-backend@1.4.0-next.1 - - @backstage/plugin-auth-backend@0.16.0-next.1 - @backstage/plugin-scaffolder-backend@1.6.0-next.1 - - @backstage/plugin-search-backend-node@1.0.2-next.1 - - @backstage/plugin-app-backend@0.3.36-next.1 - - @backstage/plugin-graphql-backend@0.1.26-next.1 - - @backstage/plugin-jenkins-backend@0.1.26-next.1 - - @backstage/plugin-rollbar-backend@0.1.33-next.1 - - @backstage/plugin-search-backend-module-pg@0.4.0-next.1 - - @backstage/plugin-kubernetes-backend@0.7.2-next.1 - - @backstage/plugin-tech-insights-backend@0.5.2-next.1 - - example-app@0.2.75-next.1 -## 0.2.75-next.0 +## 0.0.3-next.0 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.15.1-next.0 - @backstage/plugin-scaffolder-backend@1.6.0-next.0 - - @backstage/plugin-kafka-backend@0.2.29-next.0 - - @backstage/plugin-proxy-backend@0.2.30-next.0 - - @backstage/plugin-azure-devops-backend@0.3.15-next.0 - - @backstage/plugin-search-backend-node@1.0.2-next.0 - - @backstage/plugin-tech-insights-node@0.3.4-next.0 - - @backstage/backend-tasks@0.3.5-next.0 - @backstage/plugin-catalog-backend@1.3.2-next.0 - - @backstage/plugin-search-backend-module-pg@0.4.0-next.0 - - @backstage/catalog-client@1.0.5-next.0 - - @backstage/integration@1.3.1-next.0 - - @backstage/plugin-app-backend@0.3.36-next.0 - - @backstage/plugin-auth-backend@0.15.2-next.0 - - @backstage/plugin-auth-node@0.2.5-next.0 - - @backstage/plugin-code-coverage-backend@0.2.2-next.0 - - @backstage/plugin-graphql-backend@0.1.26-next.0 - - @backstage/plugin-jenkins-backend@0.1.26-next.0 - - @backstage/plugin-permission-backend@0.5.11-next.0 - - @backstage/plugin-permission-common@0.6.4-next.0 - - @backstage/plugin-permission-node@0.6.5-next.0 - - @backstage/plugin-rollbar-backend@0.1.33-next.0 - - @backstage/plugin-techdocs-backend@1.2.2-next.0 - - @backstage/plugin-todo-backend@0.1.33-next.0 - - @backstage/plugin-tech-insights-backend@0.5.2-next.0 - - @backstage/plugin-badges-backend@0.1.30-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.2-next.0 - - @backstage/plugin-kubernetes-backend@0.7.2-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.4-next.0 - - @backstage/plugin-search-backend@1.0.2-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20-next.0 - - example-app@0.2.75-next.0 - - @backstage/plugin-search-common@1.0.1-next.0 + - @backstage/backend-defaults@0.1.1-next.0 -## 0.2.74 +## 0.0.2 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.15.0 - - @backstage/plugin-kubernetes-backend@0.7.1 - - @backstage/integration@1.3.0 - @backstage/plugin-scaffolder-backend@1.5.0 - - @backstage/plugin-auth-backend@0.15.1 - - @backstage/plugin-graphql-backend@0.1.25 - - @backstage/backend-tasks@0.3.4 - - @backstage/plugin-tech-insights-node@0.3.3 + - @backstage/backend-defaults@0.1.0 - @backstage/plugin-catalog-backend@1.3.1 - - example-app@0.2.74 - - @backstage/plugin-app-backend@0.3.35 - - @backstage/plugin-auth-node@0.2.4 - - @backstage/plugin-azure-devops-backend@0.3.14 - - @backstage/plugin-badges-backend@0.1.29 - - @backstage/plugin-code-coverage-backend@0.2.1 - - @backstage/plugin-jenkins-backend@0.1.25 - - @backstage/plugin-kafka-backend@0.2.28 - - @backstage/plugin-permission-backend@0.5.10 - - @backstage/plugin-permission-node@0.6.4 - - @backstage/plugin-proxy-backend@0.2.29 - - @backstage/plugin-rollbar-backend@0.1.32 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.3 - - @backstage/plugin-search-backend@1.0.1 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.1 - - @backstage/plugin-search-backend-module-pg@0.3.6 - - @backstage/plugin-search-backend-node@1.0.1 - - @backstage/plugin-tech-insights-backend@0.5.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.19 - - @backstage/plugin-techdocs-backend@1.2.1 - - @backstage/plugin-todo-backend@0.1.32 -## 0.2.74-next.0 +## 0.0.2-next.0 ### Patch Changes - Updated dependencies - - @backstage/backend-common@0.15.0-next.0 - - @backstage/integration@1.3.0-next.0 - @backstage/plugin-scaffolder-backend@1.5.0-next.0 - - @backstage/backend-tasks@0.3.4-next.0 - - @backstage/plugin-kubernetes-backend@0.7.1-next.0 - - @backstage/plugin-tech-insights-node@0.3.3-next.0 - - @backstage/plugin-app-backend@0.3.35-next.0 - - @backstage/plugin-auth-backend@0.15.1-next.0 - - @backstage/plugin-auth-node@0.2.4-next.0 - - @backstage/plugin-azure-devops-backend@0.3.14-next.0 - - @backstage/plugin-badges-backend@0.1.29-next.0 + - @backstage/backend-app-api@0.1.1-next.0 - @backstage/plugin-catalog-backend@1.3.1-next.0 - - @backstage/plugin-code-coverage-backend@0.2.1-next.0 - - @backstage/plugin-graphql-backend@0.1.25-next.0 - - @backstage/plugin-jenkins-backend@0.1.25-next.0 - - @backstage/plugin-kafka-backend@0.2.28-next.0 - - @backstage/plugin-permission-backend@0.5.10-next.0 - - @backstage/plugin-permission-node@0.6.4-next.0 - - @backstage/plugin-proxy-backend@0.2.29-next.0 - - @backstage/plugin-rollbar-backend@0.1.32-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.3-next.0 - - @backstage/plugin-search-backend@1.0.1-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.1-next.0 - - @backstage/plugin-search-backend-module-pg@0.3.6-next.0 - - @backstage/plugin-search-backend-node@1.0.1-next.0 - - @backstage/plugin-tech-insights-backend@0.5.1-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.19-next.0 - - @backstage/plugin-techdocs-backend@1.2.1-next.0 - - @backstage/plugin-todo-backend@0.1.32-next.0 - - example-app@0.2.74-next.0 -## 0.2.73 +## 0.0.1 ### Patch Changes - Updated dependencies - - @backstage/plugin-code-coverage-backend@0.2.0 - @backstage/plugin-catalog-backend@1.3.0 - - @backstage/plugin-tech-insights-backend@0.5.0 - - @backstage/backend-common@0.14.1 - - @backstage/catalog-model@1.1.0 - - @backstage/plugin-kubernetes-backend@0.7.0 - - @backstage/plugin-search-backend@1.0.0 - - @backstage/plugin-search-backend-node@1.0.0 - - @backstage/plugin-search-common@1.0.0 - - @backstage/plugin-search-backend-module-elasticsearch@1.0.0 - @backstage/plugin-scaffolder-backend@1.4.0 - - @backstage/plugin-auth-backend@0.15.0 - - @backstage/plugin-jenkins-backend@0.1.24 - - @backstage/plugin-proxy-backend@0.2.28 - - @backstage/plugin-search-backend-module-pg@0.3.5 - - @backstage/integration@1.2.2 - - @backstage/catalog-client@1.0.4 - - @backstage/plugin-app-backend@0.3.34 - - @backstage/plugin-auth-node@0.2.3 - - @backstage/plugin-azure-devops-backend@0.3.13 - - @backstage/plugin-graphql-backend@0.1.24 - - @backstage/plugin-permission-backend@0.5.9 - - @backstage/plugin-permission-common@0.6.3 - - @backstage/plugin-permission-node@0.6.3 - - @backstage/plugin-rollbar-backend@0.1.31 - - @backstage/plugin-techdocs-backend@1.2.0 - - @backstage/plugin-todo-backend@0.1.31 - - @backstage/backend-tasks@0.3.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18 - - @backstage/plugin-tech-insights-node@0.3.2 - - @backstage/plugin-kafka-backend@0.2.27 - - @backstage/plugin-badges-backend@0.1.28 - - example-app@0.2.73 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.2 + - @backstage/backend-app-api@0.1.0 -## 0.2.73-next.3 +## 0.0.1-next.0 ### Patch Changes - Updated dependencies - - @backstage/plugin-code-coverage-backend@0.2.0-next.3 - @backstage/plugin-catalog-backend@1.3.0-next.3 - - @backstage/plugin-kubernetes-backend@0.7.0-next.3 - - @backstage/plugin-proxy-backend@0.2.28-next.1 - - @backstage/backend-common@0.14.1-next.3 - @backstage/plugin-scaffolder-backend@1.4.0-next.3 - - @backstage/catalog-client@1.0.4-next.2 - - @backstage/integration@1.2.2-next.3 - - @backstage/plugin-app-backend@0.3.34-next.3 - - @backstage/plugin-auth-backend@0.15.0-next.3 - - @backstage/plugin-auth-node@0.2.3-next.2 - - @backstage/plugin-azure-devops-backend@0.3.13-next.1 - - @backstage/plugin-graphql-backend@0.1.24-next.1 - - @backstage/plugin-jenkins-backend@0.1.24-next.3 - - @backstage/plugin-permission-backend@0.5.9-next.2 - - @backstage/plugin-permission-common@0.6.3-next.1 - - @backstage/plugin-permission-node@0.6.3-next.2 - - @backstage/plugin-rollbar-backend@0.1.31-next.1 - - @backstage/plugin-techdocs-backend@1.2.0-next.3 - - @backstage/plugin-todo-backend@0.1.31-next.2 - - @backstage/backend-tasks@0.3.3-next.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.2 - - @backstage/plugin-tech-insights-backend@0.5.0-next.3 - - @backstage/plugin-tech-insights-node@0.3.2-next.1 - - @backstage/catalog-model@1.1.0-next.3 - - @backstage/plugin-search-backend-module-elasticsearch@0.2.0-next.2 - - @backstage/plugin-search-backend-node@0.6.3-next.2 - - @backstage/plugin-search-backend@0.5.4-next.2 - - example-app@0.2.73-next.3 - -## 0.2.73-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.7.0-next.2 - - @backstage/plugin-tech-insights-backend@0.5.0-next.2 - - @backstage/plugin-jenkins-backend@0.1.24-next.2 - - @backstage/plugin-search-backend-module-pg@0.3.5-next.2 - - @backstage/plugin-scaffolder-backend@1.4.0-next.2 - - @backstage/plugin-auth-backend@0.15.0-next.2 - - @backstage/catalog-model@1.1.0-next.2 - - @backstage/plugin-kafka-backend@0.2.27-next.2 - - @backstage/backend-common@0.14.1-next.2 - - @backstage/backend-tasks@0.3.3-next.2 - - @backstage/plugin-app-backend@0.3.34-next.2 - - @backstage/plugin-catalog-backend@1.2.1-next.2 - - @backstage/plugin-code-coverage-backend@0.1.32-next.2 - - @backstage/plugin-techdocs-backend@1.2.0-next.2 - - @backstage/plugin-badges-backend@0.1.28-next.2 - - @backstage/integration@1.2.2-next.2 - - example-app@0.2.73-next.2 - -## 0.2.73-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.4.0-next.1 - - @backstage/plugin-auth-backend@0.15.0-next.1 - - @backstage/catalog-model@1.1.0-next.1 - - @backstage/backend-common@0.14.1-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@0.2.0-next.1 - - @backstage/plugin-catalog-backend@1.2.1-next.1 - - @backstage/plugin-techdocs-backend@1.2.0-next.1 - - example-app@0.2.73-next.1 - - @backstage/backend-tasks@0.3.3-next.1 - - @backstage/catalog-client@1.0.4-next.1 - - @backstage/integration@1.2.2-next.1 - - @backstage/plugin-app-backend@0.3.34-next.1 - - @backstage/plugin-auth-node@0.2.3-next.1 - - @backstage/plugin-badges-backend@0.1.28-next.1 - - @backstage/plugin-code-coverage-backend@0.1.32-next.1 - - @backstage/plugin-jenkins-backend@0.1.24-next.1 - - @backstage/plugin-kafka-backend@0.2.27-next.1 - - @backstage/plugin-kubernetes-backend@0.7.0-next.1 - - @backstage/plugin-permission-backend@0.5.9-next.1 - - @backstage/plugin-permission-common@0.6.3-next.0 - - @backstage/plugin-permission-node@0.6.3-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.1 - - @backstage/plugin-search-backend@0.5.4-next.1 - - @backstage/plugin-search-backend-module-pg@0.3.5-next.1 - - @backstage/plugin-search-backend-node@0.6.3-next.1 - - @backstage/plugin-tech-insights-backend@0.4.2-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.1 - - @backstage/plugin-todo-backend@0.1.31-next.1 - -## 0.2.73-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-tech-insights-backend@0.4.2-next.0 - - @backstage/backend-common@0.14.1-next.0 - - @backstage/catalog-model@1.1.0-next.0 - - @backstage/plugin-scaffolder-backend@1.4.0-next.0 - - @backstage/plugin-auth-backend@0.14.2-next.0 - - @backstage/plugin-kubernetes-backend@0.7.0-next.0 - - @backstage/integration@1.2.2-next.0 - - @backstage/plugin-azure-devops-backend@0.3.13-next.0 - - example-app@0.2.73-next.0 - - @backstage/backend-tasks@0.3.3-next.0 - - @backstage/plugin-app-backend@0.3.34-next.0 - - @backstage/plugin-auth-node@0.2.3-next.0 - - @backstage/plugin-badges-backend@0.1.28-next.0 - - @backstage/plugin-catalog-backend@1.2.1-next.0 - - @backstage/plugin-code-coverage-backend@0.1.32-next.0 - - @backstage/plugin-graphql-backend@0.1.24-next.0 - - @backstage/plugin-jenkins-backend@0.1.24-next.0 - - @backstage/plugin-kafka-backend@0.2.27-next.0 - - @backstage/plugin-permission-backend@0.5.9-next.0 - - @backstage/plugin-permission-node@0.6.3-next.0 - - @backstage/plugin-proxy-backend@0.2.28-next.0 - - @backstage/plugin-rollbar-backend@0.1.31-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.0 - - @backstage/plugin-search-backend@0.5.4-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.6-next.0 - - @backstage/plugin-search-backend-module-pg@0.3.5-next.0 - - @backstage/plugin-search-backend-node@0.6.3-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.0 - - @backstage/plugin-tech-insights-node@0.3.2-next.0 - - @backstage/plugin-techdocs-backend@1.1.3-next.0 - - @backstage/plugin-todo-backend@0.1.31-next.0 - - @backstage/catalog-client@1.0.4-next.0 - -## 0.2.72 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-tech-insights-backend@0.4.1 - - @backstage/plugin-catalog-backend@1.2.0 - - @backstage/plugin-auth-backend@0.14.1 - - @backstage/plugin-scaffolder-backend@1.3.0 - - @backstage/backend-tasks@0.3.2 - - @backstage/plugin-permission-node@0.6.2 - - @backstage/plugin-kubernetes-backend@0.6.0 - - @backstage/backend-common@0.14.0 - - @backstage/plugin-search-backend@0.5.3 - - @backstage/plugin-auth-node@0.2.2 - - @backstage/integration@1.2.1 - - @backstage/plugin-jenkins-backend@0.1.23 - - @backstage/plugin-search-backend-node@0.6.2 - - @backstage/catalog-client@1.0.3 - - @backstage/plugin-app-backend@0.3.33 - - @backstage/plugin-azure-devops-backend@0.3.12 - - @backstage/plugin-code-coverage-backend@0.1.31 - - @backstage/plugin-graphql-backend@0.1.23 - - @backstage/plugin-permission-backend@0.5.8 - - @backstage/plugin-permission-common@0.6.2 - - @backstage/plugin-rollbar-backend@0.1.30 - - @backstage/plugin-techdocs-backend@1.1.2 - - @backstage/plugin-todo-backend@0.1.30 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.5 - - @backstage/plugin-search-backend-module-pg@0.3.4 - - @backstage/catalog-model@1.0.3 - - @backstage/plugin-tech-insights-node@0.3.1 - - example-app@0.2.72 - - @backstage/plugin-badges-backend@0.1.27 - - @backstage/plugin-kafka-backend@0.2.26 - - @backstage/plugin-proxy-backend@0.2.27 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.17 - -## 0.2.72-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@1.3.0-next.2 - - @backstage/backend-common@0.14.0-next.2 - - @backstage/plugin-search-backend@0.5.3-next.2 - - @backstage/plugin-auth-backend@0.14.1-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.5-next.2 - - @backstage/integration@1.2.1-next.2 - - @backstage/plugin-techdocs-backend@1.1.2-next.2 - - @backstage/plugin-search-backend-node@0.6.2-next.2 - - example-app@0.2.72-next.2 - - @backstage/backend-tasks@0.3.2-next.2 - - @backstage/plugin-app-backend@0.3.33-next.2 - - @backstage/plugin-auth-node@0.2.2-next.2 - - @backstage/plugin-azure-devops-backend@0.3.12-next.2 - - @backstage/plugin-badges-backend@0.1.27-next.2 - - @backstage/plugin-catalog-backend@1.2.0-next.2 - - @backstage/plugin-code-coverage-backend@0.1.31-next.2 - - @backstage/plugin-graphql-backend@0.1.23-next.2 - - @backstage/plugin-jenkins-backend@0.1.23-next.2 - - @backstage/plugin-kafka-backend@0.2.26-next.2 - - @backstage/plugin-kubernetes-backend@0.6.0-next.2 - - @backstage/plugin-permission-backend@0.5.8-next.2 - - @backstage/plugin-permission-node@0.6.2-next.2 - - @backstage/plugin-proxy-backend@0.2.27-next.1 - - @backstage/plugin-rollbar-backend@0.1.30-next.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.1-next.1 - - @backstage/plugin-search-backend-module-pg@0.3.4-next.2 - - @backstage/plugin-tech-insights-backend@0.4.1-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.17-next.1 - - @backstage/plugin-tech-insights-node@0.3.1-next.1 - - @backstage/plugin-todo-backend@0.1.30-next.2 - -## 0.2.72-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-tech-insights-backend@0.4.1-next.1 - - @backstage/plugin-auth-backend@0.14.1-next.1 - - @backstage/plugin-jenkins-backend@0.1.23-next.1 - - @backstage/backend-tasks@0.3.2-next.1 - - @backstage/backend-common@0.13.6-next.1 - - @backstage/catalog-client@1.0.3-next.0 - - @backstage/integration@1.2.1-next.1 - - @backstage/plugin-app-backend@0.3.33-next.1 - - @backstage/plugin-auth-node@0.2.2-next.1 - - @backstage/plugin-azure-devops-backend@0.3.12-next.1 - - @backstage/plugin-catalog-backend@1.2.0-next.1 - - @backstage/plugin-code-coverage-backend@0.1.31-next.1 - - @backstage/plugin-graphql-backend@0.1.23-next.1 - - @backstage/plugin-permission-backend@0.5.8-next.1 - - @backstage/plugin-permission-common@0.6.2-next.0 - - @backstage/plugin-permission-node@0.6.2-next.1 - - @backstage/plugin-rollbar-backend@0.1.30-next.1 - - @backstage/plugin-scaffolder-backend@1.3.0-next.1 - - @backstage/plugin-techdocs-backend@1.1.2-next.1 - - @backstage/plugin-todo-backend@0.1.30-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.5-next.1 - - @backstage/plugin-search-backend-node@0.6.2-next.1 - - @backstage/catalog-model@1.0.3-next.0 - - @backstage/plugin-badges-backend@0.1.27-next.1 - - example-app@0.2.72-next.1 - - @backstage/plugin-search-backend@0.5.3-next.1 - - @backstage/plugin-kafka-backend@0.2.26-next.1 - - @backstage/plugin-kubernetes-backend@0.6.0-next.1 - - @backstage/plugin-search-backend-module-pg@0.3.4-next.1 - -## 0.2.72-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-tasks@0.3.2-next.0 - - @backstage/plugin-scaffolder-backend@1.3.0-next.0 - - @backstage/plugin-kubernetes-backend@0.6.0-next.0 - - @backstage/backend-common@0.13.6-next.0 - - @backstage/plugin-auth-backend@0.14.1-next.0 - - @backstage/integration@1.2.1-next.0 - - @backstage/plugin-search-backend-node@0.6.2-next.0 - - @backstage/plugin-catalog-backend@1.2.0-next.0 - - @backstage/plugin-auth-node@0.2.2-next.0 - - @backstage/plugin-techdocs-backend@1.1.2-next.0 - - example-app@0.2.72-next.0 - - @backstage/plugin-app-backend@0.3.33-next.0 - - @backstage/plugin-azure-devops-backend@0.3.12-next.0 - - @backstage/plugin-badges-backend@0.1.27-next.0 - - @backstage/plugin-code-coverage-backend@0.1.31-next.0 - - @backstage/plugin-graphql-backend@0.1.23-next.0 - - @backstage/plugin-jenkins-backend@0.1.23-next.0 - - @backstage/plugin-kafka-backend@0.2.26-next.0 - - @backstage/plugin-permission-backend@0.5.8-next.0 - - @backstage/plugin-permission-node@0.6.2-next.0 - - @backstage/plugin-proxy-backend@0.2.27-next.0 - - @backstage/plugin-rollbar-backend@0.1.30-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.1-next.0 - - @backstage/plugin-search-backend@0.5.3-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.5-next.0 - - @backstage/plugin-search-backend-module-pg@0.3.4-next.0 - - @backstage/plugin-tech-insights-backend@0.4.1-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.17-next.0 - - @backstage/plugin-tech-insights-node@0.3.1-next.0 - - @backstage/plugin-todo-backend@0.1.30-next.0 - -## 0.2.71 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.3 - - @backstage/plugin-auth-backend@0.14.0 - - @backstage/plugin-kubernetes-backend@0.5.1 - - @backstage/plugin-catalog-backend@1.1.2 - - @backstage/plugin-tech-insights-backend@0.4.0 - - @backstage/plugin-scaffolder-backend@1.2.0 - - @backstage/backend-tasks@0.3.1 - - @backstage/integration@1.2.0 - - @backstage/plugin-tech-insights-node@0.3.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16 - - @backstage/plugin-rollbar-backend@0.1.29 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.4 - - @backstage/config@1.0.1 - - @backstage/plugin-app-backend@0.3.32 - - @backstage/plugin-techdocs-backend@1.1.1 - - @backstage/plugin-search-backend-node@0.6.1 - - @backstage/plugin-search-backend-module-pg@0.3.3 - - @backstage/plugin-jenkins-backend@0.1.22 - - @backstage/plugin-search-backend@0.5.2 - - @backstage/plugin-auth-node@0.2.1 - - @backstage/plugin-azure-devops-backend@0.3.11 - - example-app@0.2.71 - - @backstage/catalog-client@1.0.2 - - @backstage/catalog-model@1.0.2 - - @backstage/plugin-badges-backend@0.1.26 - - @backstage/plugin-code-coverage-backend@0.1.30 - - @backstage/plugin-graphql-backend@0.1.22 - - @backstage/plugin-kafka-backend@0.2.25 - - @backstage/plugin-permission-backend@0.5.7 - - @backstage/plugin-permission-common@0.6.1 - - @backstage/plugin-permission-node@0.6.1 - - @backstage/plugin-proxy-backend@0.2.26 - - @backstage/plugin-todo-backend@0.1.29 - -## 0.2.71-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.3-next.2 - - @backstage/plugin-kubernetes-backend@0.5.1-next.1 - - @backstage/plugin-catalog-backend@1.1.2-next.2 - - @backstage/backend-tasks@0.3.1-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.4.0-next.1 - - @backstage/plugin-scaffolder-backend@1.2.0-next.1 - - @backstage/config@1.0.1-next.0 - - @backstage/plugin-search-backend-node@0.6.1-next.1 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.4-next.1 - - @backstage/plugin-search-backend-module-pg@0.3.3-next.1 - - @backstage/plugin-azure-devops-backend@0.3.11-next.1 - - example-app@0.2.71-next.2 - - @backstage/catalog-model@1.0.2-next.0 - - @backstage/integration@1.2.0-next.1 - - @backstage/plugin-app-backend@0.3.32-next.1 - - @backstage/plugin-auth-backend@0.13.1-next.2 - - @backstage/plugin-auth-node@0.2.1-next.1 - - @backstage/plugin-badges-backend@0.1.26-next.1 - - @backstage/plugin-code-coverage-backend@0.1.30-next.1 - - @backstage/plugin-graphql-backend@0.1.22-next.1 - - @backstage/plugin-jenkins-backend@0.1.22-next.1 - - @backstage/plugin-kafka-backend@0.2.25-next.1 - - @backstage/plugin-permission-backend@0.5.7-next.1 - - @backstage/plugin-permission-common@0.6.1-next.0 - - @backstage/plugin-permission-node@0.6.1-next.1 - - @backstage/plugin-proxy-backend@0.2.26-next.1 - - @backstage/plugin-rollbar-backend@0.1.29-next.2 - - @backstage/plugin-search-backend@0.5.2-next.1 - - @backstage/plugin-tech-insights-backend@0.4.0-next.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16-next.2 - - @backstage/plugin-tech-insights-node@0.3.0-next.2 - - @backstage/plugin-techdocs-backend@1.1.1-next.1 - - @backstage/plugin-todo-backend@0.1.29-next.1 - - @backstage/catalog-client@1.0.2-next.0 - -## 0.2.71-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.13.1-next.1 - - @backstage/plugin-tech-insights-backend@0.4.0-next.1 - - @backstage/backend-common@0.13.3-next.1 - - @backstage/plugin-tech-insights-node@0.3.0-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16-next.1 - - @backstage/plugin-catalog-backend@1.1.2-next.1 - - @backstage/plugin-rollbar-backend@0.1.29-next.1 - - example-app@0.2.71-next.1 - -## 0.2.71-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.3-next.0 - - @backstage/plugin-scaffolder-backend@1.2.0-next.0 - - @backstage/plugin-kubernetes-backend@0.5.1-next.0 - - @backstage/integration@1.2.0-next.0 - - @backstage/plugin-catalog-backend@1.1.2-next.0 - - @backstage/plugin-app-backend@0.3.32-next.0 - - @backstage/plugin-auth-backend@0.13.1-next.0 - - @backstage/plugin-rollbar-backend@0.1.29-next.0 - - @backstage/plugin-techdocs-backend@1.1.1-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.4-next.0 - - @backstage/plugin-jenkins-backend@0.1.22-next.0 - - @backstage/plugin-search-backend@0.5.2-next.0 - - @backstage/backend-tasks@0.3.1-next.0 - - @backstage/plugin-auth-node@0.2.1-next.0 - - example-app@0.2.71-next.0 - - @backstage/plugin-azure-devops-backend@0.3.11-next.0 - - @backstage/plugin-badges-backend@0.1.26-next.0 - - @backstage/plugin-code-coverage-backend@0.1.30-next.0 - - @backstage/plugin-graphql-backend@0.1.22-next.0 - - @backstage/plugin-kafka-backend@0.2.25-next.0 - - @backstage/plugin-permission-backend@0.5.7-next.0 - - @backstage/plugin-permission-node@0.6.1-next.0 - - @backstage/plugin-proxy-backend@0.2.26-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.7-next.0 - - @backstage/plugin-search-backend-module-pg@0.3.3-next.0 - - @backstage/plugin-search-backend-node@0.6.1-next.0 - - @backstage/plugin-tech-insights-backend@0.3.1-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.16-next.0 - - @backstage/plugin-tech-insights-node@0.2.10-next.0 - - @backstage/plugin-todo-backend@0.1.29-next.0 - -## 0.2.70 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.1.0 - - @backstage/plugin-techdocs-backend@1.1.0 - - @backstage/plugin-scaffolder-backend@1.1.0 - - @backstage/integration@1.1.0 - - @backstage/plugin-search-backend@0.5.0 - - @backstage/plugin-auth-backend@0.13.0 - - @backstage/backend-tasks@0.3.0 - - @backstage/plugin-permission-common@0.6.0 - - @backstage/plugin-permission-node@0.6.0 - - @backstage/catalog-model@1.0.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.15 - - @backstage/plugin-kafka-backend@0.2.24 - - @backstage/plugin-auth-node@0.2.0 - - @backstage/plugin-jenkins-backend@0.1.20 - - @backstage/plugin-badges-backend@0.1.25 - - @backstage/plugin-tech-insights-node@0.2.9 - - @backstage/plugin-todo-backend@0.1.28 - - @backstage/backend-common@0.13.2 - - @backstage/plugin-kubernetes-backend@0.5.0 - - @backstage/plugin-search-backend-node@0.6.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.3 - - @backstage/plugin-search-backend-module-pg@0.3.2 - - @backstage/plugin-permission-backend@0.5.6 - - @backstage/plugin-tech-insights-backend@0.3.0 - - @backstage/plugin-azure-devops-backend@0.3.10 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.6 - - example-app@0.2.70 - - @backstage/catalog-client@1.0.1 - - @backstage/plugin-app-backend@0.3.31 - - @backstage/plugin-code-coverage-backend@0.1.29 - - @backstage/plugin-graphql-backend@0.1.21 - - @backstage/plugin-proxy-backend@0.2.25 - - @backstage/plugin-rollbar-backend@0.1.28 - -## 0.2.70-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.13.0-next.2 - - @backstage/plugin-catalog-backend@1.1.0-next.3 - - @backstage/plugin-kafka-backend@0.2.24-next.1 - - @backstage/plugin-search-backend@0.5.0-next.2 - - @backstage/plugin-permission-common@0.6.0-next.1 - - @backstage/plugin-permission-node@0.6.0-next.2 - - @backstage/plugin-jenkins-backend@0.1.20-next.2 - - @backstage/plugin-todo-backend@0.1.28-next.2 - - @backstage/backend-common@0.13.2-next.2 - - @backstage/plugin-kubernetes-backend@0.5.0-next.1 - - @backstage/plugin-search-backend-node@0.6.0-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.6-next.2 - - @backstage/integration@1.1.0-next.2 - - @backstage/plugin-techdocs-backend@1.1.0-next.2 - - example-app@0.2.70-next.2 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.3-next.1 - - @backstage/plugin-search-backend-module-pg@0.3.2-next.1 - - @backstage/plugin-app-backend@0.3.31-next.1 - -## 0.2.70-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.1.0-next.1 - - @backstage/plugin-techdocs-backend@1.0.1-next.1 - - @backstage/plugin-scaffolder-backend@1.1.0-next.1 - - @backstage/integration@1.1.0-next.1 - - @backstage/plugin-search-backend@0.5.0-next.1 - - @backstage/backend-tasks@0.3.0-next.1 - - @backstage/plugin-permission-common@0.6.0-next.0 - - @backstage/plugin-permission-node@0.6.0-next.1 - - @backstage/plugin-badges-backend@0.1.25-next.1 - - @backstage/plugin-tech-insights-node@0.2.9-next.1 - - @backstage/plugin-permission-backend@0.5.6-next.1 - - @backstage/backend-common@0.13.2-next.1 - - @backstage/plugin-auth-backend@0.13.0-next.1 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.15-next.1 - - @backstage/plugin-tech-insights-backend@0.3.0-next.1 - - @backstage/plugin-jenkins-backend@0.1.20-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.6-next.1 - - @backstage/plugin-code-coverage-backend@0.1.29-next.1 - - @backstage/plugin-todo-backend@0.1.28-next.1 - - example-app@0.2.70-next.1 - -## 0.2.70-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.0.1-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.15-next.0 - - @backstage/plugin-search-backend@0.5.0-next.0 - - @backstage/plugin-auth-node@0.2.0-next.0 - - @backstage/plugin-auth-backend@0.13.0-next.0 - - @backstage/plugin-catalog-backend@1.0.1-next.0 - - @backstage/plugin-search-backend-node@0.5.3-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.3-next.0 - - @backstage/plugin-search-backend-module-pg@0.3.2-next.0 - - @backstage/backend-common@0.13.2-next.0 - - @backstage/integration@1.0.1-next.0 - - @backstage/plugin-tech-insights-backend@0.2.11-next.0 - - @backstage/plugin-techdocs-backend@1.0.1-next.0 - - @backstage/plugin-jenkins-backend@0.1.20-next.0 - - example-app@0.2.70-next.0 - - @backstage/catalog-client@1.0.1-next.0 - - @backstage/plugin-badges-backend@0.1.25-next.0 - - @backstage/plugin-code-coverage-backend@0.1.29-next.0 - - @backstage/plugin-kafka-backend@0.2.24-next.0 - - @backstage/plugin-kubernetes-backend@0.4.14-next.0 - - @backstage/plugin-scaffolder-backend@1.0.1-next.0 - - @backstage/plugin-todo-backend@0.1.28-next.0 - - @backstage/plugin-app-backend@0.3.31-next.0 - - @backstage/plugin-permission-backend@0.5.6-next.0 - - @backstage/plugin-permission-node@0.5.6-next.0 - - @backstage/backend-tasks@0.2.2-next.0 - - @backstage/plugin-azure-devops-backend@0.3.10-next.0 - - @backstage/plugin-graphql-backend@0.1.21-next.0 - - @backstage/plugin-proxy-backend@0.2.25-next.0 - - @backstage/plugin-rollbar-backend@0.1.28-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.6-next.0 - - @backstage/plugin-tech-insights-node@0.2.9-next.0 - -## 0.2.69 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-app-backend@0.3.30 - - @backstage/plugin-azure-devops-backend@0.3.9 - - @backstage/plugin-badges-backend@0.1.24 - - @backstage/plugin-catalog-backend@1.0.0 - - @backstage/plugin-jenkins-backend@0.1.19 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.5 - - @backstage/plugin-tech-insights-backend@0.2.10 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.14 - - @backstage/plugin-todo-backend@0.1.27 - - @backstage/plugin-kubernetes-backend@0.4.13 - - @backstage/plugin-scaffolder-backend@1.0.0 - - @backstage/backend-common@0.13.1 - - @backstage/backend-tasks@0.2.1 - - @backstage/plugin-auth-backend@0.12.2 - - @backstage/plugin-code-coverage-backend@0.1.28 - - @backstage/catalog-model@1.0.0 - - @backstage/integration@1.0.0 - - @backstage/catalog-client@1.0.0 - - @backstage/config@1.0.0 - - @backstage/plugin-techdocs-backend@1.0.0 - - @backstage/plugin-permission-common@0.5.3 - - @backstage/plugin-search-backend-node@0.5.2 - - example-app@0.2.69 - - @backstage/plugin-auth-node@0.1.6 - - @backstage/plugin-graphql-backend@0.1.20 - - @backstage/plugin-kafka-backend@0.2.23 - - @backstage/plugin-permission-backend@0.5.5 - - @backstage/plugin-permission-node@0.5.5 - - @backstage/plugin-proxy-backend@0.2.24 - - @backstage/plugin-rollbar-backend@0.1.27 - - @backstage/plugin-search-backend@0.4.8 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.2 - - @backstage/plugin-tech-insights-node@0.2.8 - -## 0.2.68 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.0 - - @backstage/backend-tasks@0.2.0 - - @backstage/plugin-app-backend@0.3.29 - - @backstage/plugin-auth-backend@0.12.1 - - @backstage/plugin-catalog-backend@0.24.0 - - @backstage/plugin-scaffolder-backend@0.18.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.4 - - @backstage/plugin-kubernetes-backend@0.4.12 - - @backstage/plugin-rollbar-backend@0.1.26 - - @backstage/plugin-techdocs-backend@0.14.2 - - @backstage/catalog-model@0.13.0 - - @backstage/plugin-badges-backend@0.1.23 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.1 - - @backstage/plugin-search-backend-module-pg@0.3.1 - - @backstage/plugin-search-backend-node@0.5.1 - - @backstage/plugin-search-backend@0.4.7 - - @backstage/catalog-client@0.9.0 - - example-app@0.2.68 - - @backstage/plugin-auth-node@0.1.5 - - @backstage/plugin-azure-devops-backend@0.3.8 - - @backstage/plugin-code-coverage-backend@0.1.27 - - @backstage/plugin-graphql-backend@0.1.19 - - @backstage/plugin-jenkins-backend@0.1.18 - - @backstage/plugin-kafka-backend@0.2.22 - - @backstage/plugin-permission-backend@0.5.4 - - @backstage/plugin-permission-node@0.5.4 - - @backstage/plugin-proxy-backend@0.2.23 - - @backstage/plugin-tech-insights-backend@0.2.9 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.13 - - @backstage/plugin-tech-insights-node@0.2.7 - - @backstage/plugin-todo-backend@0.1.26 - -## 0.2.68-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.0-next.0 - - @backstage/backend-tasks@0.2.0-next.0 - - @backstage/plugin-app-backend@0.3.29-next.0 - - @backstage/plugin-auth-backend@0.12.1-next.0 - - @backstage/plugin-catalog-backend@0.24.0-next.0 - - @backstage/plugin-scaffolder-backend@0.18.0-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.4-next.0 - - @backstage/plugin-kubernetes-backend@0.4.12-next.0 - - @backstage/plugin-rollbar-backend@0.1.26-next.0 - - @backstage/plugin-techdocs-backend@0.14.2-next.0 - - @backstage/catalog-model@0.13.0-next.0 - - @backstage/plugin-badges-backend@0.1.23-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.1-next.0 - - @backstage/plugin-search-backend-module-pg@0.3.1-next.0 - - @backstage/plugin-search-backend-node@0.5.1-next.0 - - @backstage/plugin-search-backend@0.4.7-next.0 - - @backstage/catalog-client@0.9.0-next.0 - - @backstage/plugin-auth-node@0.1.5-next.0 - - @backstage/plugin-azure-devops-backend@0.3.8-next.0 - - @backstage/plugin-code-coverage-backend@0.1.27-next.0 - - @backstage/plugin-graphql-backend@0.1.19-next.0 - - @backstage/plugin-jenkins-backend@0.1.18-next.0 - - @backstage/plugin-kafka-backend@0.2.22-next.0 - - @backstage/plugin-permission-backend@0.5.4-next.0 - - @backstage/plugin-permission-node@0.5.4-next.0 - - @backstage/plugin-proxy-backend@0.2.23-next.0 - - @backstage/plugin-tech-insights-backend@0.2.9-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.13-next.0 - - @backstage/plugin-tech-insights-node@0.2.7-next.0 - - @backstage/plugin-todo-backend@0.1.26-next.0 - - example-app@0.2.68-next.0 - -## 0.2.67 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@0.12.0 - - @backstage/catalog-client@0.8.0 - - @backstage/plugin-catalog-backend@0.23.0 - - @backstage/backend-common@0.12.0 - - @backstage/plugin-scaffolder-backend@0.17.3 - - @backstage/plugin-techdocs-backend@0.14.1 - - @backstage/plugin-auth-backend@0.12.0 - - @backstage/plugin-badges-backend@0.1.22 - - @backstage/plugin-code-coverage-backend@0.1.26 - - @backstage/plugin-jenkins-backend@0.1.17 - - @backstage/plugin-todo-backend@0.1.25 - - @backstage/integration@0.8.0 - - @backstage/plugin-permission-common@0.5.2 - - @backstage/plugin-permission-node@0.5.3 - - @backstage/plugin-search-backend-node@0.5.0 - - @backstage/plugin-search-backend-module-pg@0.3.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.1.0 - - @backstage/plugin-tech-insights-backend@0.2.8 - - example-app@0.2.67 - - @backstage/plugin-auth-node@0.1.4 - - @backstage/plugin-kafka-backend@0.2.21 - - @backstage/plugin-kubernetes-backend@0.4.11 - - @backstage/backend-tasks@0.1.10 - - @backstage/plugin-app-backend@0.3.28 - - @backstage/plugin-azure-devops-backend@0.3.7 - - @backstage/plugin-graphql-backend@0.1.18 - - @backstage/plugin-permission-backend@0.5.3 - - @backstage/plugin-proxy-backend@0.2.22 - - @backstage/plugin-rollbar-backend@0.1.25 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.3 - - @backstage/plugin-search-backend@0.4.6 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.12 - - @backstage/plugin-tech-insights-node@0.2.6 - -## 0.2.66 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.11.0 - - @backstage/plugin-catalog-backend@0.22.0 - - @backstage/plugin-scaffolder-backend@0.17.0 - - @backstage/plugin-graphql-backend@0.1.17 - - @backstage/plugin-auth-backend@0.11.0 - - @backstage/plugin-kubernetes-backend@0.4.10 - - @backstage/plugin-code-coverage-backend@0.1.25 - - @backstage/plugin-jenkins-backend@0.1.16 - - @backstage/plugin-tech-insights-backend@0.2.7 - - @backstage/plugin-todo-backend@0.1.24 - - @backstage/catalog-model@0.11.0 - - @backstage/catalog-client@0.7.2 - - @backstage/plugin-badges-backend@0.1.21 - - @backstage/backend-tasks@0.1.9 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.2 - - @backstage/plugin-techdocs-backend@0.14.0 - - @backstage/plugin-permission-node@0.5.2 - - @backstage/integration@0.7.5 - - example-app@0.2.66 - - @backstage/plugin-app-backend@0.3.27 - - @backstage/plugin-auth-node@0.1.3 - - @backstage/plugin-azure-devops-backend@0.3.6 - - @backstage/plugin-kafka-backend@0.2.20 - - @backstage/plugin-permission-backend@0.5.2 - - @backstage/plugin-proxy-backend@0.2.21 - - @backstage/plugin-rollbar-backend@0.1.24 - - @backstage/plugin-search-backend@0.4.5 - - @backstage/plugin-search-backend-module-pg@0.2.9 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.11 - - @backstage/plugin-tech-insights-node@0.2.5 - -## 0.2.66 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.9 - - @backstage/backend-tasks@0.1.8 - - @backstage/catalog-client@0.7.1 - - @backstage/catalog-model@0.10.1 - - @backstage/config@0.1.15 - - @backstage/integration@0.7.4 - - @backstage/plugin-app-backend@0.3.26 - - @backstage/plugin-auth-backend@0.10.2 - - @backstage/plugin-auth-node@0.1.2 - - @backstage/plugin-azure-devops-backend@0.3.5 - - @backstage/plugin-badges-backend@0.1.20 - - @backstage/plugin-catalog-backend@0.21.5 - - @backstage/plugin-code-coverage-backend@0.1.24 - - @backstage/plugin-graphql-backend@0.1.16 - - @backstage/plugin-jenkins-backend@0.1.15 - - @backstage/plugin-kafka-backend@0.2.19 - - @backstage/plugin-kubernetes-backend@0.4.9 - - @backstage/plugin-permission-backend@0.5.1 - - @backstage/plugin-permission-common@0.5.1 - - @backstage/plugin-permission-node@0.5.1 - - @backstage/plugin-proxy-backend@0.2.20 - - @backstage/plugin-rollbar-backend@0.1.23 - - @backstage/plugin-scaffolder-backend@0.16.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.1 - - @backstage/plugin-search-backend@0.4.4 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.10 - - @backstage/plugin-search-backend-module-pg@0.2.8 - - @backstage/plugin-search-backend-node@0.4.7 - - @backstage/plugin-tech-insights-backend@0.2.6 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.10 - - @backstage/plugin-tech-insights-node@0.2.4 - - @backstage/plugin-techdocs-backend@0.13.5 - - @backstage/plugin-todo-backend@0.1.23 - -## 0.2.65 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-techdocs-backend@0.13.4 - - @backstage/plugin-catalog-backend@0.21.4 - - @backstage/backend-common@0.10.8 - - @backstage/catalog-client@0.7.0 - - @backstage/integration@0.7.3 - - @backstage/plugin-auth-backend@0.10.1 - - @backstage/plugin-auth-node@0.1.1 - - @backstage/plugin-permission-backend@0.5.0 - - @backstage/plugin-permission-common@0.5.0 - - @backstage/plugin-rollbar-backend@0.1.22 - - @backstage/plugin-scaffolder-backend@0.16.0 - - @backstage/backend-tasks@0.1.7 - - @backstage/catalog-model@0.10.0 - - @backstage/config@0.1.14 - - @backstage/plugin-app-backend@0.3.25 - - @backstage/plugin-azure-devops-backend@0.3.4 - - @backstage/plugin-badges-backend@0.1.19 - - @backstage/plugin-code-coverage-backend@0.1.23 - - @backstage/plugin-graphql-backend@0.1.15 - - @backstage/plugin-jenkins-backend@0.1.14 - - @backstage/plugin-kafka-backend@0.2.18 - - @backstage/plugin-kubernetes-backend@0.4.8 - - @backstage/plugin-permission-node@0.5.0 - - @backstage/plugin-proxy-backend@0.2.19 - - @backstage/plugin-scaffolder-backend-module-rails@0.3.0 - - @backstage/plugin-search-backend@0.4.3 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.9 - - @backstage/plugin-search-backend-module-pg@0.2.7 - - @backstage/plugin-search-backend-node@0.4.6 - - @backstage/plugin-tech-insights-backend@0.2.5 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.9 - - @backstage/plugin-tech-insights-node@0.2.3 - - @backstage/plugin-todo-backend@0.1.22 - - example-app@0.2.65 - -## 0.2.64 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-client@0.6.0 - - @backstage/plugin-auth-backend@0.10.0 - - @backstage/backend-common@0.10.7 - - @backstage/backend-tasks@0.1.6 - - @backstage/plugin-app-backend@0.3.24 - - @backstage/plugin-catalog-backend@0.21.3 - - @backstage/plugin-code-coverage-backend@0.1.22 - - @backstage/plugin-scaffolder-backend@0.15.24 - - @backstage/plugin-search-backend-module-pg@0.2.6 - - @backstage/plugin-tech-insights-backend@0.2.4 - - @backstage/plugin-techdocs-backend@0.13.3 - - @backstage/plugin-auth-node@0.1.0 - - @backstage/plugin-permission-backend@0.4.3 - - @backstage/plugin-search-backend@0.4.2 - - @backstage/plugin-badges-backend@0.1.18 - - @backstage/plugin-jenkins-backend@0.1.13 - - @backstage/plugin-todo-backend@0.1.21 - - @backstage/plugin-permission-node@0.4.3 - - example-app@0.2.64 - - @backstage/plugin-azure-devops-backend@0.3.3 - - @backstage/plugin-graphql-backend@0.1.14 - - @backstage/plugin-kafka-backend@0.2.17 - - @backstage/plugin-kubernetes-backend@0.4.7 - - @backstage/plugin-proxy-backend@0.2.18 - - @backstage/plugin-rollbar-backend@0.1.21 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.6 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.8 - - @backstage/plugin-tech-insights-node@0.2.2 - -## 0.2.64-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.10.0-next.0 - - @backstage/backend-common@0.10.7-next.0 - - @backstage/backend-tasks@0.1.6-next.0 - - @backstage/plugin-app-backend@0.3.24-next.0 - - @backstage/plugin-catalog-backend@0.21.3-next.0 - - @backstage/plugin-code-coverage-backend@0.1.22-next.0 - - @backstage/plugin-scaffolder-backend@0.15.24-next.0 - - @backstage/plugin-search-backend-module-pg@0.2.6-next.0 - - @backstage/plugin-tech-insights-backend@0.2.4-next.0 - - @backstage/plugin-techdocs-backend@0.13.3-next.0 - - example-app@0.2.64-next.0 - - @backstage/plugin-azure-devops-backend@0.3.3-next.0 - - @backstage/plugin-badges-backend@0.1.18-next.0 - - @backstage/plugin-graphql-backend@0.1.14-next.0 - - @backstage/plugin-jenkins-backend@0.1.13-next.0 - - @backstage/plugin-kafka-backend@0.2.17-next.0 - - @backstage/plugin-kubernetes-backend@0.4.7-next.0 - - @backstage/plugin-permission-backend@0.4.3-next.0 - - @backstage/plugin-permission-node@0.4.3-next.0 - - @backstage/plugin-proxy-backend@0.2.18-next.0 - - @backstage/plugin-rollbar-backend@0.1.21-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.6-next.0 - - @backstage/plugin-search-backend@0.4.2-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.8-next.0 - - @backstage/plugin-tech-insights-node@0.2.2-next.0 - - @backstage/plugin-todo-backend@0.1.21-next.0 - -## 0.2.63 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.9.0 - - @backstage/plugin-rollbar-backend@0.1.20 - - @backstage/plugin-catalog-backend@0.21.2 - - @backstage/plugin-scaffolder-backend@0.15.23 - - @backstage/plugin-proxy-backend@0.2.17 - - @backstage/backend-common@0.10.6 - - example-app@0.2.63 - - @backstage/backend-tasks@0.1.5 - - @backstage/plugin-app-backend@0.3.23 - - @backstage/plugin-azure-devops-backend@0.3.2 - - @backstage/plugin-badges-backend@0.1.17 - - @backstage/plugin-code-coverage-backend@0.1.21 - - @backstage/plugin-graphql-backend@0.1.13 - - @backstage/plugin-jenkins-backend@0.1.12 - - @backstage/plugin-kafka-backend@0.2.16 - - @backstage/plugin-kubernetes-backend@0.4.6 - - @backstage/plugin-permission-backend@0.4.2 - - @backstage/plugin-permission-node@0.4.2 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.5 - - @backstage/plugin-search-backend@0.4.1 - - @backstage/plugin-search-backend-module-pg@0.2.5 - - @backstage/plugin-tech-insights-backend@0.2.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.7 - - @backstage/plugin-tech-insights-node@0.2.1 - - @backstage/plugin-techdocs-backend@0.13.2 - - @backstage/plugin-todo-backend@0.1.20 - -## 0.2.63-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.9.0-next.1 - - @backstage/backend-common@0.10.6-next.0 - - example-app@0.2.63-next.1 - - @backstage/plugin-catalog-backend@0.21.2-next.1 - - @backstage/plugin-techdocs-backend@0.13.2-next.0 - - @backstage/backend-tasks@0.1.5-next.0 - - @backstage/plugin-app-backend@0.3.23-next.0 - - @backstage/plugin-azure-devops-backend@0.3.2-next.0 - - @backstage/plugin-badges-backend@0.1.17-next.0 - - @backstage/plugin-code-coverage-backend@0.1.21-next.0 - - @backstage/plugin-graphql-backend@0.1.13-next.0 - - @backstage/plugin-jenkins-backend@0.1.12-next.0 - - @backstage/plugin-kafka-backend@0.2.16-next.0 - - @backstage/plugin-kubernetes-backend@0.4.6-next.0 - - @backstage/plugin-permission-backend@0.4.2-next.1 - - @backstage/plugin-permission-node@0.4.2-next.1 - - @backstage/plugin-proxy-backend@0.2.17-next.1 - - @backstage/plugin-rollbar-backend@0.1.20-next.1 - - @backstage/plugin-scaffolder-backend@0.15.23-next.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.5-next.1 - - @backstage/plugin-search-backend@0.4.1-next.1 - - @backstage/plugin-search-backend-module-pg@0.2.5-next.0 - - @backstage/plugin-tech-insights-backend@0.2.3-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.7-next.0 - - @backstage/plugin-tech-insights-node@0.2.1-next.0 - - @backstage/plugin-todo-backend@0.1.20-next.0 - -## 0.2.63-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.9.0-next.0 - - @backstage/plugin-rollbar-backend@0.1.20-next.0 - - @backstage/plugin-catalog-backend@0.21.2-next.0 - - @backstage/plugin-scaffolder-backend@0.15.23-next.0 - - @backstage/plugin-proxy-backend@0.2.17-next.0 - - @backstage/plugin-permission-backend@0.4.2-next.0 - - @backstage/plugin-permission-node@0.4.2-next.0 - - @backstage/plugin-search-backend@0.4.1-next.0 - - example-app@0.2.63-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.5-next.0 - -## 0.2.62 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-search-backend-node@0.4.5 - - @backstage/plugin-catalog-backend@0.21.1 - - @backstage/plugin-scaffolder-backend@0.15.22 - - @backstage/plugin-kubernetes-backend@0.4.5 - - @backstage/plugin-auth-backend@0.8.0 - - @backstage/plugin-search-backend@0.4.0 - - @backstage/plugin-tech-insights-backend@0.2.2 - - @backstage/plugin-techdocs-backend@0.13.1 - - @backstage/backend-common@0.10.5 - - example-app@0.2.62 - - @backstage/plugin-permission-backend@0.4.1 - - @backstage/plugin-permission-node@0.4.1 - -## 0.2.61 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.7.0 - - @backstage/plugin-permission-backend@0.4.0 - - @backstage/plugin-catalog-backend@0.21.0 - - @backstage/plugin-kubernetes-backend@0.4.4 - - @backstage/integration@0.7.2 - - @backstage/plugin-permission-common@0.4.0 - - @backstage/plugin-search-backend@0.3.1 - - @backstage/plugin-techdocs-backend@0.13.0 - - @backstage/backend-common@0.10.4 - - @backstage/config@0.1.13 - - @backstage/plugin-app-backend@0.3.22 - - @backstage/plugin-permission-node@0.4.0 - - @backstage/plugin-scaffolder-backend@0.15.21 - - @backstage/plugin-tech-insights-backend@0.2.0 - - @backstage/plugin-tech-insights-node@0.2.0 - - @backstage/catalog-model@0.9.10 - - example-app@0.2.61 - - @backstage/backend-tasks@0.1.4 - - @backstage/catalog-client@0.5.5 - - @backstage/plugin-azure-devops-backend@0.3.1 - - @backstage/plugin-badges-backend@0.1.16 - - @backstage/plugin-code-coverage-backend@0.1.20 - - @backstage/plugin-graphql-backend@0.1.12 - - @backstage/plugin-jenkins-backend@0.1.11 - - @backstage/plugin-kafka-backend@0.2.15 - - @backstage/plugin-proxy-backend@0.2.16 - - @backstage/plugin-rollbar-backend@0.1.19 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.4 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.8 - - @backstage/plugin-search-backend-module-pg@0.2.4 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.6 - - @backstage/plugin-todo-backend@0.1.19 - -## 0.2.61-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.7.0-next.0 - - @backstage/plugin-permission-backend@0.4.0-next.0 - - @backstage/plugin-catalog-backend@0.21.0-next.0 - - @backstage/plugin-permission-common@0.4.0-next.0 - - @backstage/backend-common@0.10.4-next.0 - - @backstage/config@0.1.13-next.0 - - @backstage/plugin-app-backend@0.3.22-next.0 - - @backstage/plugin-permission-node@0.4.0-next.0 - - @backstage/plugin-tech-insights-backend@0.2.0-next.0 - - @backstage/plugin-tech-insights-node@0.2.0-next.0 - - @backstage/catalog-model@0.9.10-next.0 - - example-app@0.2.61-next.0 - - @backstage/plugin-scaffolder-backend@0.15.21-next.0 - - @backstage/backend-tasks@0.1.4-next.0 - - @backstage/catalog-client@0.5.5-next.0 - - @backstage/integration@0.7.2-next.0 - - @backstage/plugin-azure-devops-backend@0.3.1-next.0 - - @backstage/plugin-badges-backend@0.1.16-next.0 - - @backstage/plugin-code-coverage-backend@0.1.20-next.0 - - @backstage/plugin-graphql-backend@0.1.12-next.0 - - @backstage/plugin-jenkins-backend@0.1.11-next.0 - - @backstage/plugin-kafka-backend@0.2.15-next.0 - - @backstage/plugin-kubernetes-backend@0.4.4-next.0 - - @backstage/plugin-proxy-backend@0.2.16-next.0 - - @backstage/plugin-rollbar-backend@0.1.19-next.0 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.4-next.0 - - @backstage/plugin-search-backend@0.3.1-next.0 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.8-next.0 - - @backstage/plugin-search-backend-module-pg@0.2.4-next.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.6-next.0 - - @backstage/plugin-techdocs-backend@0.12.4-next.0 - - @backstage/plugin-todo-backend@0.1.19-next.0 - -## 0.2.60 - -### Patch Changes - -- Updated dependencies - - @backstage/config@0.1.12 - - @backstage/plugin-scaffolder-backend@0.15.20 - - @backstage/integration@0.7.1 - - @backstage/backend-common@0.10.3 - - @backstage/plugin-todo-backend@0.1.18 - - @backstage/plugin-catalog-backend@0.20.0 - - @backstage/plugin-tech-insights-backend@0.1.5 - - @backstage/plugin-permission-node@0.3.0 - - @backstage/plugin-auth-backend@0.6.2 - - @backstage/plugin-code-coverage-backend@0.1.19 - - @backstage/plugin-search-backend-node@0.4.4 - - @backstage/plugin-techdocs-backend@0.12.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.5 - - @backstage/plugin-permission-backend@0.3.0 - - @backstage/plugin-graphql-backend@0.1.11 - - @backstage/plugin-kubernetes-backend@0.4.3 - - example-app@0.2.60 - - @backstage/backend-tasks@0.1.3 - - @backstage/catalog-client@0.5.4 - - @backstage/catalog-model@0.9.9 - - @backstage/plugin-badges-backend@0.1.15 - - @backstage/plugin-kafka-backend@0.2.14 - - @backstage/plugin-permission-common@0.3.1 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.3 - -## 0.2.59 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-rollbar-backend@0.1.18 - - @backstage/plugin-auth-backend@0.6.0 - - @backstage/backend-common@0.10.1 - - @backstage/plugin-app-backend@0.3.21 - - @backstage/plugin-catalog-backend@0.19.4 - - @backstage/plugin-scaffolder-backend@0.15.19 - - @backstage/integration@0.7.0 - - @backstage/plugin-techdocs-backend@0.12.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.4 - - @backstage/plugin-permission-backend@0.2.3 - - @backstage/plugin-permission-node@0.2.3 - - @backstage/plugin-code-coverage-backend@0.1.18 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.2 - - @backstage/plugin-todo-backend@0.1.17 - -## 0.2.58 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.0 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.1 - - @backstage/catalog-client@0.5.3 - - @backstage/plugin-rollbar-backend@0.1.17 - - @backstage/plugin-auth-backend@0.5.2 - - @backstage/plugin-permission-common@0.3.0 - - @backstage/plugin-search-backend@0.3.0 - - @backstage/plugin-techdocs-backend@0.12.1 - - @backstage/plugin-jenkins-backend@0.1.10 - - @backstage/plugin-permission-node@0.2.2 - - example-app@0.2.58 - - @backstage/plugin-app-backend@0.3.20 - - @backstage/plugin-azure-devops-backend@0.2.6 - - @backstage/plugin-badges-backend@0.1.14 - - @backstage/plugin-catalog-backend@0.19.3 - - @backstage/plugin-code-coverage-backend@0.1.17 - - @backstage/plugin-graphql-backend@0.1.10 - - @backstage/plugin-kafka-backend@0.2.13 - - @backstage/plugin-kubernetes-backend@0.4.1 - - @backstage/plugin-permission-backend@0.2.2 - - @backstage/plugin-proxy-backend@0.2.15 - - @backstage/plugin-scaffolder-backend@0.15.18 - - @backstage/plugin-search-backend-module-pg@0.2.3 - - @backstage/plugin-tech-insights-backend@0.1.4 - - @backstage/plugin-tech-insights-node@0.1.2 - - @backstage/plugin-todo-backend@0.1.16 - -## 0.2.57 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-search-backend-module-elasticsearch@0.0.7 - - @backstage/plugin-catalog-backend@0.19.2 - - @backstage/plugin-scaffolder-backend@0.15.17 - - @backstage/backend-common@0.9.14 - - @backstage/plugin-azure-devops-backend@0.2.5 - - @backstage/plugin-auth-backend@0.5.1 - - @backstage/catalog-model@0.9.8 - - example-app@0.2.57 - -## 0.2.56 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.5.0 - - @backstage/plugin-scaffolder-backend@0.15.16 - - @backstage/plugin-kubernetes-backend@0.4.0 - - @backstage/backend-common@0.9.13 - - @backstage/plugin-catalog-backend@0.19.1 - - @backstage/plugin-search-backend@0.2.8 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.6 - - @backstage/plugin-search-backend-module-pg@0.2.2 - - @backstage/plugin-techdocs-backend@0.12.0 - - @backstage/plugin-todo-backend@0.1.15 - - @backstage/plugin-scaffolder-backend-module-rails@0.2.0 - - @backstage/plugin-azure-devops-backend@0.2.4 - - example-app@0.2.56 - -## 0.2.55 - -### Patch Changes - -- Updated dependencies - - @backstage/integration@0.6.10 - - @backstage/plugin-scaffolder-backend@0.15.15 - - @backstage/plugin-auth-backend@0.4.10 - - @backstage/plugin-kubernetes-backend@0.3.20 - - @backstage/plugin-badges-backend@0.1.13 - - @backstage/plugin-catalog-backend@0.19.0 - - @backstage/plugin-code-coverage-backend@0.1.16 - - @backstage/plugin-jenkins-backend@0.1.9 - - @backstage/plugin-tech-insights-backend@0.1.3 - - @backstage/plugin-techdocs-backend@0.11.0 - - @backstage/plugin-todo-backend@0.1.14 - - @backstage/backend-common@0.9.12 - - @backstage/plugin-azure-devops-backend@0.2.3 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.2 - - @backstage/plugin-tech-insights-node@0.1.1 - - example-app@0.2.55 - -## 0.2.54 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.3.19 - - @backstage/plugin-tech-insights-backend@0.1.2 - - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.1 - - @backstage/plugin-auth-backend@0.4.9 - - @backstage/plugin-scaffolder-backend@0.15.14 - - @backstage/plugin-catalog-backend@0.18.0 - - @backstage/plugin-kafka-backend@0.2.12 - - @backstage/backend-common@0.9.11 - - @backstage/plugin-azure-devops-backend@0.2.2 - - @backstage/plugin-badges-backend@0.1.12 - - @backstage/plugin-code-coverage-backend@0.1.15 - - @backstage/plugin-jenkins-backend@0.1.8 - - @backstage/plugin-proxy-backend@0.2.14 - - @backstage/plugin-rollbar-backend@0.1.16 - - @backstage/plugin-search-backend@0.2.7 - - @backstage/plugin-techdocs-backend@0.10.9 - -## 0.2.52 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.9.9 - - @backstage/plugin-jenkins-backend@0.1.7 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.5 - - @backstage/plugin-scaffolder-backend@0.15.12 - - @backstage/plugin-azure-devops-backend@0.2.0 - - @backstage/catalog-client@0.5.1 - - @backstage/plugin-auth-backend@0.4.7 - - @backstage/plugin-catalog-backend@0.17.3 - - @backstage/plugin-scaffolder-backend-module-rails@0.1.7 - -## 0.2.50 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.4.4 - - @backstage/integration@0.6.8 - - @backstage/plugin-scaffolder-backend@0.15.8 - - @backstage/plugin-catalog-backend@0.17.0 - - @backstage/plugin-azure-devops-backend@0.1.2 - - @backstage/plugin-code-coverage-backend@0.1.13 - - @backstage/plugin-kubernetes-backend@0.3.17 - - example-app@0.2.50 - -## 0.2.49 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@0.16.0 - - @backstage/catalog-model@0.9.4 - - @backstage/plugin-proxy-backend@0.2.13 - - @backstage/plugin-auth-backend@0.4.3 - - @backstage/backend-common@0.9.6 - - @backstage/catalog-client@0.5.0 - - @backstage/integration@0.6.7 - - @backstage/plugin-scaffolder-backend@0.15.7 - - example-app@0.2.49 - - @backstage/plugin-badges-backend@0.1.11 - - @backstage/plugin-code-coverage-backend@0.1.12 - - @backstage/plugin-jenkins-backend@0.1.6 - - @backstage/plugin-techdocs-backend@0.10.4 - - @backstage/plugin-todo-backend@0.1.13 - -## 0.2.48 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.9.5 - - @backstage/plugin-catalog-backend@0.15.0 - - @backstage/plugin-azure-devops-backend@0.1.1 - - @backstage/integration@0.6.6 - - @backstage/plugin-auth-backend@0.4.2 - - example-app@0.2.48 - -## 0.2.47 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@0.14.0 - - @backstage/integration@0.6.5 - - @backstage/catalog-client@0.4.0 - - @backstage/catalog-model@0.9.3 - - @backstage/backend-common@0.9.4 - - @backstage/config@0.1.10 - - @backstage/plugin-kafka-backend@0.2.10 - - @backstage/plugin-kubernetes-backend@0.3.16 - - @backstage/plugin-rollbar-backend@0.1.15 - - @backstage/plugin-search-backend-module-pg@0.2.1 - - example-app@0.2.47 - - @backstage/plugin-auth-backend@0.4.1 - - @backstage/plugin-badges-backend@0.1.10 - - @backstage/plugin-code-coverage-backend@0.1.11 - - @backstage/plugin-jenkins-backend@0.1.5 - - @backstage/plugin-scaffolder-backend@0.15.6 - - @backstage/plugin-techdocs-backend@0.10.3 - - @backstage/plugin-todo-backend@0.1.12 - -## 0.2.46 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.4.0 - - @backstage/plugin-scaffolder-backend@0.15.5 - - @backstage/backend-common@0.9.3 - - @backstage/plugin-catalog-backend@0.13.8 - - @backstage/plugin-techdocs-backend@0.10.2 - - @backstage/integration@0.6.4 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.4 - - example-app@0.2.46 - -## 0.2.44 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@0.13.6 - - @backstage/plugin-scaffolder-backend@0.15.3 - - @backstage/plugin-techdocs-backend@0.10.1 - - @backstage/plugin-auth-backend@0.3.24 - - @backstage/integration@0.6.3 - - @backstage/plugin-search-backend@0.2.6 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.3 - - @backstage/plugin-search-backend-module-pg@0.2.0 - - @backstage/plugin-search-backend-node@0.4.2 - - @backstage/catalog-model@0.9.1 - - @backstage/backend-common@0.9.1 - - example-app@0.2.44 - -## 0.2.43 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.9.0 - - @backstage/plugin-catalog-backend@0.13.5 - - @backstage/plugin-search-backend-module-pg@0.1.3 - - @backstage/plugin-auth-backend@0.3.23 - - @backstage/plugin-scaffolder-backend@0.15.2 - - @backstage/integration@0.6.2 - - @backstage/config@0.1.8 - - @backstage/plugin-kubernetes-backend@0.3.15 - - @backstage/plugin-techdocs-backend@0.10.0 - - @backstage/plugin-jenkins-backend@0.1.4 - - @backstage/plugin-app-backend@0.3.16 - - @backstage/plugin-badges-backend@0.1.9 - - @backstage/plugin-code-coverage-backend@0.1.10 - - @backstage/plugin-graphql-backend@0.1.9 - - @backstage/plugin-kafka-backend@0.2.9 - - @backstage/plugin-proxy-backend@0.2.12 - - @backstage/plugin-rollbar-backend@0.1.14 - - @backstage/plugin-scaffolder-backend-module-rails@0.1.5 - - @backstage/plugin-search-backend@0.2.5 - - @backstage/plugin-todo-backend@0.1.11 - - example-app@0.2.43 - -## 0.2.41 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-auth-backend@0.3.20 - - @backstage/integration@0.6.0 - - @backstage/plugin-scaffolder-backend@0.15.0 - - @backstage/backend-common@0.8.9 - - @backstage/plugin-kubernetes-backend@0.3.14 - - @backstage/plugin-search-backend-module-elasticsearch@0.0.2 - - @backstage/plugin-search-backend-module-pg@0.1.1 - - @backstage/plugin-catalog-backend@0.13.2 - - @backstage/plugin-code-coverage-backend@0.1.9 - - @backstage/plugin-scaffolder-backend-module-rails@0.1.4 - - @backstage/plugin-techdocs-backend@0.9.2 - - @backstage/plugin-todo-backend@0.1.9 - - example-app@0.2.41 - -## 0.2.38 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-kubernetes-backend@0.3.11 - - @backstage/catalog-client@0.3.17 - - @backstage/plugin-auth-backend@0.3.18 - - @backstage/plugin-jenkins-backend@0.1.2 - - @backstage/backend-common@0.8.7 - - @backstage/plugin-techdocs-backend@0.9.0 - - @backstage/plugin-scaffolder-backend@0.14.1 - -## 0.2.37 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.8.6 - - @backstage/plugin-scaffolder-backend@0.14.0 - - @backstage/plugin-catalog-backend@0.13.0 - - @backstage/plugin-auth-backend@0.3.17 - - @backstage/plugin-scaffolder-backend-module-rails@0.1.3 - - @backstage/plugin-search-backend-node@0.4.0 - - @backstage/plugin-techdocs-backend@0.8.7 - - @backstage/plugin-app-backend@0.3.15 - - @backstage/plugin-kubernetes-backend@0.3.10 - - @backstage/plugin-rollbar-backend@0.1.13 - - example-app@0.2.37 - - @backstage/plugin-search-backend@0.2.3 - -## 0.2.36 - -### Patch Changes - -- Updated dependencies - - @backstage/integration@0.5.8 - - @backstage/plugin-scaffolder-backend@0.13.0 - - @backstage/catalog-model@0.9.0 - - @backstage/plugin-catalog-backend@0.12.0 - - @backstage/backend-common@0.8.5 - - @backstage/plugin-search-backend-node@0.3.0 - - example-app@0.2.36 - - @backstage/plugin-scaffolder-backend-module-rails@0.1.2 - - @backstage/catalog-client@0.3.16 - - @backstage/plugin-auth-backend@0.3.16 - - @backstage/plugin-badges-backend@0.1.8 - - @backstage/plugin-code-coverage-backend@0.1.8 - - @backstage/plugin-kafka-backend@0.2.8 - - @backstage/plugin-kubernetes-backend@0.3.9 - - @backstage/plugin-techdocs-backend@0.8.6 - - @backstage/plugin-todo-backend@0.1.8 - - @backstage/plugin-search-backend@0.2.2 - -## 0.2.35 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-scaffolder-backend@0.12.4 - - @backstage/backend-common@0.8.4 - - @backstage/plugin-auth-backend@0.3.15 - - @backstage/plugin-catalog-backend@0.11.0 - - @backstage/plugin-techdocs-backend@0.8.5 - - @backstage/catalog-client@0.3.15 - - @backstage/plugin-kafka-backend@0.2.7 - -## 0.2.32 - -### Patch Changes - -- Updated dependencies [9c63be545] -- Updated dependencies [92963779b] -- Updated dependencies [27a9b503a] -- Updated dependencies [66c6bfebd] -- Updated dependencies [55a253de2] -- Updated dependencies [70bc30c5b] -- Updated dependencies [db1c8f93b] -- Updated dependencies [5aff84759] -- Updated dependencies [f26e6008f] -- Updated dependencies [eda9dbd5f] -- Updated dependencies [4f8cf50fe] -- Updated dependencies [875809a59] - - @backstage/plugin-catalog-backend@0.10.2 - - @backstage/backend-common@0.8.2 - - @backstage/catalog-model@0.8.2 - - @backstage/plugin-scaffolder-backend@0.12.0 - - @backstage/catalog-client@0.3.13 - - @backstage/plugin-search-backend-node@0.2.0 - - @backstage/plugin-search-backend@0.2.0 - - @backstage/plugin-proxy-backend@0.2.9 - - example-app@0.2.32 - -## 0.2.30 - -### Patch Changes - -- Updated dependencies [0fd4ea443] -- Updated dependencies [add62a455] -- Updated dependencies [260aaa684] -- Updated dependencies [704875e26] - - @backstage/plugin-catalog-backend@0.10.0 - - @backstage/catalog-client@0.3.12 - - @backstage/catalog-model@0.8.0 - - @backstage/plugin-scaffolder-backend@0.11.4 - - example-app@0.2.30 - - @backstage/plugin-auth-backend@0.3.12 - - @backstage/plugin-badges-backend@0.1.6 - - @backstage/plugin-code-coverage-backend@0.1.6 - - @backstage/plugin-kafka-backend@0.2.6 - - @backstage/plugin-kubernetes-backend@0.3.8 - - @backstage/plugin-techdocs-backend@0.8.2 - - @backstage/plugin-todo-backend@0.1.6 - -## 0.2.28 - -### Patch Changes - -- Updated dependencies [062bbf90f] -- Updated dependencies [22fd8ce2a] -- Updated dependencies [10c008a3a] -- Updated dependencies [82ca1ac22] -- Updated dependencies [f9fb4a205] -- Updated dependencies [9a207f052] -- Updated dependencies [16be1d093] -- Updated dependencies [fd39d4662] -- Updated dependencies [f9f9d633d] - - @backstage/plugin-scaffolder-backend@0.11.1 - - @backstage/backend-common@0.8.0 - - @backstage/catalog-model@0.7.9 - - @backstage/plugin-catalog-backend@0.9.0 - - @backstage/plugin-kubernetes-backend@0.3.7 - - example-app@0.2.28 - - @backstage/plugin-app-backend@0.3.13 - - @backstage/plugin-auth-backend@0.3.10 - - @backstage/plugin-badges-backend@0.1.4 - - @backstage/plugin-code-coverage-backend@0.1.5 - - @backstage/plugin-graphql-backend@0.1.8 - - @backstage/plugin-kafka-backend@0.2.5 - - @backstage/plugin-proxy-backend@0.2.8 - - @backstage/plugin-rollbar-backend@0.1.11 - - @backstage/plugin-search-backend@0.1.5 - - @backstage/plugin-techdocs-backend@0.8.1 - - @backstage/plugin-todo-backend@0.1.5 - -## 0.2.27 - -### Patch Changes - -- Updated dependencies [e0bfd3d44] -- Updated dependencies [e0bfd3d44] -- Updated dependencies [e0bfd3d44] -- Updated dependencies [38ca05168] -- Updated dependencies [b219821a0] -- Updated dependencies [69eefb5ae] -- Updated dependencies [f53fba29f] -- Updated dependencies [75c8cec39] -- Updated dependencies [227439a72] -- Updated dependencies [cdb3426e5] -- Updated dependencies [d8b81fd28] -- Updated dependencies [d1b1306d9] - - @backstage/plugin-scaffolder-backend@0.11.0 - - @backstage/backend-common@0.7.0 - - @backstage/plugin-techdocs-backend@0.8.0 - - @backstage/plugin-catalog-backend@0.8.2 - - @backstage/plugin-kubernetes-backend@0.3.6 - - @backstage/plugin-proxy-backend@0.2.7 - - @backstage/catalog-model@0.7.8 - - @backstage/config@0.1.5 - - @backstage/catalog-client@0.3.11 - - example-app@0.2.27 - - @backstage/plugin-app-backend@0.3.12 - - @backstage/plugin-auth-backend@0.3.9 - - @backstage/plugin-badges-backend@0.1.3 - - @backstage/plugin-code-coverage-backend@0.1.4 - - @backstage/plugin-graphql-backend@0.1.7 - - @backstage/plugin-kafka-backend@0.2.4 - - @backstage/plugin-rollbar-backend@0.1.10 - - @backstage/plugin-search-backend@0.1.4 - - @backstage/plugin-todo-backend@0.1.4 - -## 0.2.25 - -### Patch Changes - -- Updated dependencies [b9b2b4b76] -- Updated dependencies [84c54474d] -- Updated dependencies [49574a8a3] -- Updated dependencies [d367f63b5] -- Updated dependencies [5fe62f124] -- Updated dependencies [09b5fcf2e] -- Updated dependencies [55b2fc0c0] -- Updated dependencies [c42cd1daa] -- Updated dependencies [b42531cfe] -- Updated dependencies [c2306f898] - - @backstage/plugin-search-backend@0.1.3 - - @backstage/plugin-search-backend-node@0.1.3 - - @backstage/plugin-scaffolder-backend@0.10.0 - - @backstage/plugin-rollbar-backend@0.1.9 - - @backstage/backend-common@0.6.3 - - @backstage/plugin-catalog-backend@0.8.0 - - @backstage/plugin-code-coverage-backend@0.1.2 - - @backstage/plugin-kubernetes-backend@0.3.5 - - example-app@0.2.25 - -## 0.2.22 - -### Patch Changes - -- Updated dependencies [f03a52f5b] -- Updated dependencies [676ede643] -- Updated dependencies [1ac6a5233] -- Updated dependencies [2ab6f3ff0] -- Updated dependencies [0d55dcc74] -- Updated dependencies [29e1789e1] -- Updated dependencies [f1b2c1d2c] -- Updated dependencies [60e463c8d] -- Updated dependencies [676ede643] -- Updated dependencies [b196a4569] -- Updated dependencies [8488a1a96] -- Updated dependencies [37e3a69f5] -- Updated dependencies [6b2d54fd6] -- Updated dependencies [44590510d] -- Updated dependencies [164cc4c53] - - @backstage/plugin-kafka-backend@0.2.3 - - @backstage/plugin-catalog-backend@0.7.0 - - @backstage/plugin-kubernetes-backend@0.3.3 - - @backstage/plugin-scaffolder-backend@0.9.4 - - @backstage/plugin-auth-backend@0.3.7 - - @backstage/catalog-client@0.3.9 - - @backstage/plugin-todo-backend@0.1.3 - - @backstage/catalog-model@0.7.5 - - @backstage/backend-common@0.6.1 - -## 0.2.21 - -### Patch Changes - -- Updated dependencies [a2a3c7803] -- Updated dependencies [9f2e51e89] -- Updated dependencies [4d248725e] -- Updated dependencies [aaeb7ecf3] -- Updated dependencies [449776cd6] -- Updated dependencies [91e87c055] -- Updated dependencies [36d933ec5] -- Updated dependencies [113d3d59e] -- Updated dependencies [f47e11427] -- Updated dependencies [c862b3f36] - - @backstage/plugin-kubernetes-backend@0.3.2 - - @backstage/plugin-scaffolder-backend@0.9.3 - - @backstage/plugin-search-backend@0.1.2 - - @backstage/plugin-search-backend-node@0.1.2 - - @backstage/plugin-techdocs-backend@0.7.0 - - @backstage/plugin-auth-backend@0.3.6 - - @backstage/plugin-todo-backend@0.1.2 - - @backstage/plugin-catalog-backend@0.6.7 - - example-app@0.2.21 - -## 0.2.20 - -### Patch Changes - -- Updated dependencies [010aed784] -- Updated dependencies [8686eb38c] -- Updated dependencies [e7baa0d2e] -- Updated dependencies [8b4f7e42a] -- Updated dependencies [8686eb38c] -- Updated dependencies [0434853a5] -- Updated dependencies [4bc98a5b9] -- Updated dependencies [d2f4efc5d] -- Updated dependencies [8686eb38c] -- Updated dependencies [424742dc1] -- Updated dependencies [1f98a6ff8] -- Updated dependencies [8b5e59750] -- Updated dependencies [8686eb38c] - - @backstage/plugin-catalog-backend@0.6.6 - - @backstage/catalog-client@0.3.8 - - @backstage/plugin-techdocs-backend@0.6.5 - - @backstage/plugin-scaffolder-backend@0.9.2 - - @backstage/backend-common@0.6.0 - - @backstage/config@0.1.4 - - @backstage/plugin-auth-backend@0.3.5 - - @backstage/plugin-kubernetes-backend@0.3.1 - - example-app@0.2.20 - - @backstage/plugin-app-backend@0.3.10 - - @backstage/plugin-graphql-backend@0.1.6 - - @backstage/plugin-kafka-backend@0.2.2 - - @backstage/plugin-proxy-backend@0.2.6 - - @backstage/plugin-rollbar-backend@0.1.8 - - @backstage/plugin-todo-backend@0.1.1 - -## 0.2.19 - -### Patch Changes - -- Updated dependencies [5d7834baf] -- Updated dependencies [9ef5a126d] -- Updated dependencies [d7245b733] -- Updated dependencies [393b623ae] -- Updated dependencies [d7245b733] -- Updated dependencies [0b42fff22] -- Updated dependencies [0b42fff22] -- Updated dependencies [2ef5bc7ea] -- Updated dependencies [c532c1682] -- Updated dependencies [761698831] -- Updated dependencies [aa095e469] -- Updated dependencies [761698831] -- Updated dependencies [f98f212e4] -- Updated dependencies [9581ff0b4] -- Updated dependencies [93c62c755] -- Updated dependencies [02d78290a] -- Updated dependencies [a501128db] -- Updated dependencies [8de9963f0] -- Updated dependencies [5f1b7ea35] -- Updated dependencies [2e57922de] -- Updated dependencies [e2c1b3fb6] - - @backstage/plugin-kubernetes-backend@0.3.0 - - @backstage/plugin-catalog-backend@0.6.5 - - @backstage/backend-common@0.5.6 - - @backstage/plugin-app-backend@0.3.9 - - @backstage/plugin-scaffolder-backend@0.9.1 - - @backstage/catalog-model@0.7.4 - - @backstage/catalog-client@0.3.7 - - @backstage/plugin-techdocs-backend@0.6.4 - - @backstage/plugin-auth-backend@0.3.4 - - example-app@0.2.19 - -## 0.2.18 - -### Patch Changes - -- Updated dependencies [12d8f27a6] -- Updated dependencies [52b5bc3e2] -- Updated dependencies [ecdd407b1] -- Updated dependencies [4fbc9df79] -- Updated dependencies [12d8f27a6] -- Updated dependencies [497859088] -- Updated dependencies [1987c9341] -- Updated dependencies [f31b76b44] -- Updated dependencies [15eee03bc] -- Updated dependencies [f43192207] -- Updated dependencies [8adb48df4] -- Updated dependencies [e3adec2bd] -- Updated dependencies [9ce68b677] -- Updated dependencies [8106c9528] -- Updated dependencies [d0ed25196] -- Updated dependencies [96ccc8f69] -- Updated dependencies [3af994c81] - - @backstage/plugin-scaffolder-backend@0.9.0 - - @backstage/plugin-techdocs-backend@0.6.3 - - @backstage/plugin-catalog-backend@0.6.4 - - @backstage/plugin-kafka-backend@0.2.1 - - @backstage/catalog-model@0.7.3 - - @backstage/backend-common@0.5.5 - - @backstage/plugin-proxy-backend@0.2.5 - - @backstage/plugin-auth-backend@0.3.3 - - @backstage/plugin-kubernetes-backend@0.2.8 - - example-app@0.2.18 - -## 0.2.17 - -### Patch Changes - -- Updated dependencies [a70af22a2] -- Updated dependencies [ec504e7b4] -- Updated dependencies [a5f42cf66] -- Updated dependencies [f37992797] -- Updated dependencies [bad21a085] -- Updated dependencies [1c06cb312] -- Updated dependencies [2499f6cde] -- Updated dependencies [a1f5e6545] - - @backstage/plugin-kubernetes-backend@0.2.7 - - @backstage/plugin-auth-backend@0.3.2 - - @backstage/plugin-scaffolder-backend@0.8.0 - - @backstage/plugin-techdocs-backend@0.6.2 - - @backstage/catalog-model@0.7.2 - - @backstage/plugin-app-backend@0.3.8 - - @backstage/plugin-catalog-backend@0.6.3 - - @backstage/config@0.1.3 - - example-app@0.2.17 - -## 0.2.15 - -### Patch Changes - -- Updated dependencies [1deb31141] -- Updated dependencies [6ed2b47d6] -- Updated dependencies [77ad0003a] -- Updated dependencies [d2441aee3] -- Updated dependencies [727f0deec] -- Updated dependencies [fb53eb7cb] -- Updated dependencies [07bafa248] -- Updated dependencies [ffffea8e6] -- Updated dependencies [f3fbfb452] -- Updated dependencies [615103a63] -- Updated dependencies [84364b35c] -- Updated dependencies [82b2c11b6] -- Updated dependencies [965e200c6] -- Updated dependencies [5a5163519] -- Updated dependencies [82b2c11b6] -- Updated dependencies [08142b256] -- Updated dependencies [08142b256] - - @backstage/plugin-auth-backend@0.3.0 - - @backstage/plugin-scaffolder-backend@0.7.0 - - @backstage/plugin-catalog-backend@0.6.1 - - @backstage/plugin-app-backend@0.3.7 - - example-app@0.2.15 - - @backstage/backend-common@0.5.3 - - @backstage/plugin-techdocs-backend@0.6.0 - -## 0.2.14 - -### Patch Changes - -- Updated dependencies [c777df180] -- Updated dependencies [2430ee7c2] -- Updated dependencies [3149bfe63] -- Updated dependencies [6e612ce25] -- Updated dependencies [e44925723] -- Updated dependencies [9d6ef14bc] -- Updated dependencies [a26668913] -- Updated dependencies [025e122c3] -- Updated dependencies [e9aab60c7] -- Updated dependencies [24e47ef1e] -- Updated dependencies [7881f2117] -- Updated dependencies [529d16d27] -- Updated dependencies [cdea0baf1] -- Updated dependencies [11cb5ef94] - - @backstage/plugin-techdocs-backend@0.5.5 - - @backstage/backend-common@0.5.2 - - @backstage/plugin-catalog-backend@0.6.0 - - @backstage/catalog-model@0.7.1 - - example-app@0.2.14 - - @backstage/plugin-scaffolder-backend@0.6.0 - - @backstage/plugin-app-backend@0.3.6 - -## 0.2.13 - -### Patch Changes - -- Updated dependencies [26a3a6cf0] -- Updated dependencies [681111228] -- Updated dependencies [664dd08c9] -- Updated dependencies [9dd057662] -- Updated dependencies [234e7d985] -- Updated dependencies [d7b1d317f] -- Updated dependencies [a91aa6bf2] -- Updated dependencies [39b05b9ae] -- Updated dependencies [4eaa06057] - - @backstage/backend-common@0.5.1 - - @backstage/plugin-scaffolder-backend@0.5.2 - - @backstage/plugin-kubernetes-backend@0.2.6 - - @backstage/plugin-catalog-backend@0.5.5 - - @backstage/plugin-kafka-backend@0.2.0 - - @backstage/plugin-auth-backend@0.2.12 - - example-app@0.2.13 - - @backstage/plugin-app-backend@0.3.5 - -## 0.2.12 - -### Patch Changes - -- Updated dependencies [def2307f3] -- Updated dependencies [d54857099] -- Updated dependencies [0b135e7e0] -- Updated dependencies [318a6af9f] -- Updated dependencies [294a70cab] -- Updated dependencies [ac7be581a] -- Updated dependencies [0ea032763] -- Updated dependencies [5345a1f98] -- Updated dependencies [ed6baab66] -- Updated dependencies [ad838c02f] -- Updated dependencies [a5e27d5c1] -- Updated dependencies [0643a3336] -- Updated dependencies [a2291d7cc] -- Updated dependencies [f9ba00a1c] -- Updated dependencies [09a370426] -- Updated dependencies [a93f42213] - - @backstage/catalog-model@0.7.0 - - @backstage/plugin-catalog-backend@0.5.4 - - @backstage/plugin-kubernetes-backend@0.2.5 - - @backstage/backend-common@0.5.0 - - @backstage/plugin-scaffolder-backend@0.5.0 - - @backstage/plugin-techdocs-backend@0.5.4 - - @backstage/plugin-auth-backend@0.2.11 - - example-app@0.2.12 - - @backstage/plugin-kafka-backend@0.1.1 - - @backstage/plugin-app-backend@0.3.4 - - @backstage/plugin-graphql-backend@0.1.5 - - @backstage/plugin-proxy-backend@0.2.4 - - @backstage/plugin-rollbar-backend@0.1.7 - -## 0.2.11 - -### Patch Changes - -- cc068c0d6: Bump the gitbeaker dependencies to 28.x. - - To update your own installation, go through the `package.json` files of all of - your packages, and ensure that all dependencies on `@gitbeaker/node` or - `@gitbeaker/core` are at version `^28.0.2`. Then run `yarn install` at the root - of your repo. - -- Updated dependencies [68ad5af51] -- Updated dependencies [5a9a7e7c2] -- Updated dependencies [f3b064e1c] -- Updated dependencies [94fdf4955] -- Updated dependencies [cc068c0d6] -- Updated dependencies [ade6b3bdf] -- Updated dependencies [468579734] -- Updated dependencies [cb7af51e7] -- Updated dependencies [abbee6fff] -- Updated dependencies [147fadcb9] -- Updated dependencies [711ba55a2] - - @backstage/plugin-techdocs-backend@0.5.3 - - @backstage/plugin-kubernetes-backend@0.2.4 - - @backstage/catalog-model@0.6.1 - - @backstage/plugin-catalog-backend@0.5.3 - - @backstage/plugin-scaffolder-backend@0.4.1 - - @backstage/plugin-auth-backend@0.2.10 - - @backstage/backend-common@0.4.3 - -## 0.2.10 - -### Patch Changes - -- Updated dependencies [5eb8c9b9e] -- Updated dependencies [7e3451700] - - @backstage/plugin-scaffolder-backend@0.4.0 - -## 0.2.8 - -### Patch Changes - -- 7cfcd58ee: use node 14 for backend Dockerfile -- Updated dependencies [19554f6d6] -- Updated dependencies [33a82a713] -- Updated dependencies [5de26b9a6] -- Updated dependencies [30d6c78fb] -- Updated dependencies [5084e5039] -- Updated dependencies [a8573e53b] -- Updated dependencies [aed8f7f12] - - @backstage/plugin-scaffolder-backend@0.3.6 - - @backstage/plugin-catalog-backend@0.5.1 - - @backstage/plugin-techdocs-backend@0.5.0 - - example-app@0.2.8 - -## 0.2.7 - -### Patch Changes - -- Updated dependencies [c6eeefa35] -- Updated dependencies [fb386b760] -- Updated dependencies [c911061b7] -- Updated dependencies [7c3ffc0cd] -- Updated dependencies [dae4f3983] -- Updated dependencies [7b15cc271] -- Updated dependencies [e7496dc3e] -- Updated dependencies [1d1c2860f] -- Updated dependencies [0e6298f7e] -- Updated dependencies [8dd0a906d] -- Updated dependencies [4eafdec4a] -- Updated dependencies [6b37c95bf] -- Updated dependencies [8c31c681c] -- Updated dependencies [7b98e7fee] -- Updated dependencies [ac3560b42] -- Updated dependencies [94c65a9d4] -- Updated dependencies [0097057ed] - - @backstage/plugin-catalog-backend@0.5.0 - - @backstage/catalog-model@0.6.0 - - @backstage/plugin-techdocs-backend@0.4.0 - - @backstage/plugin-auth-backend@0.2.7 - - @backstage/backend-common@0.4.1 - - @backstage/plugin-scaffolder-backend@0.3.5 - - example-app@0.2.7 - - @backstage/plugin-kubernetes-backend@0.2.3 - -## 0.2.6 - -### Patch Changes - -- 1e22f8e0b: Unify `dockerode` library and type dependency versions -- Updated dependencies [6e8bb3ac0] -- Updated dependencies [e708679d7] -- Updated dependencies [047c018c9] -- Updated dependencies [38e24db00] -- Updated dependencies [e3bd9fc2f] -- Updated dependencies [12bbd748c] -- Updated dependencies [38d63fbe1] -- Updated dependencies [1e22f8e0b] -- Updated dependencies [83b6e0c1f] -- Updated dependencies [e3bd9fc2f] - - @backstage/plugin-catalog-backend@0.4.0 - - @backstage/backend-common@0.4.0 - - @backstage/config@0.1.2 - - @backstage/plugin-scaffolder-backend@0.3.4 - - @backstage/plugin-techdocs-backend@0.3.2 - - @backstage/catalog-model@0.5.0 - - example-app@0.2.6 - - @backstage/plugin-app-backend@0.3.3 - - @backstage/plugin-auth-backend@0.2.6 - - @backstage/plugin-graphql-backend@0.1.4 - - @backstage/plugin-kubernetes-backend@0.2.2 - - @backstage/plugin-proxy-backend@0.2.3 - - @backstage/plugin-rollbar-backend@0.1.5 - -## 0.2.5 - -### Patch Changes - -- Updated dependencies [ae95c7ff3] -- Updated dependencies [b4488ddb0] -- Updated dependencies [612368274] -- Updated dependencies [6a6c7c14e] -- Updated dependencies [08835a61d] -- Updated dependencies [a9fd599f7] -- Updated dependencies [e42402b47] -- Updated dependencies [bcc211a08] -- Updated dependencies [3619ea4c4] - - @backstage/plugin-techdocs-backend@0.3.1 - - @backstage/plugin-catalog-backend@0.3.0 - - @backstage/backend-common@0.3.3 - - @backstage/plugin-proxy-backend@0.2.2 - - @backstage/catalog-model@0.4.0 - - @backstage/plugin-kubernetes-backend@0.2.1 - - @backstage/plugin-app-backend@0.3.2 - - example-app@0.2.5 - - @backstage/plugin-auth-backend@0.2.5 - - @backstage/plugin-scaffolder-backend@0.3.3 - -## 0.2.4 - -### Patch Changes - -- Updated dependencies [50eff1d00] -- Updated dependencies [ff1301d28] -- Updated dependencies [4b53294a6] -- Updated dependencies [3aa7efb3f] -- Updated dependencies [1ec19a3f4] -- Updated dependencies [ab94c9542] -- Updated dependencies [3a201c5d5] -- Updated dependencies [2daf18e80] -- Updated dependencies [069cda35f] -- Updated dependencies [b3d4e4e57] -- Updated dependencies [700a212b4] - - @backstage/plugin-auth-backend@0.2.4 - - @backstage/plugin-app-backend@0.3.1 - - @backstage/plugin-techdocs-backend@0.3.0 - - @backstage/backend-common@0.3.2 - - @backstage/plugin-catalog-backend@0.2.3 - - @backstage/catalog-model@0.3.1 - - @backstage/plugin-rollbar-backend@0.1.4 - - example-app@0.2.4 - -## 0.2.3 - -### Patch Changes - -- Updated dependencies [1166fcc36] -- Updated dependencies [bff3305aa] -- Updated dependencies [0c2121240] -- Updated dependencies [ef2831dde] -- Updated dependencies [1185919f3] -- Updated dependencies [475fc0aaa] -- Updated dependencies [b47dce06f] -- Updated dependencies [5a1d8dca3] - - @backstage/catalog-model@0.3.0 - - @backstage/plugin-kubernetes-backend@0.2.0 - - @backstage/backend-common@0.3.1 - - @backstage/plugin-catalog-backend@0.2.2 - - @backstage/plugin-scaffolder-backend@0.3.2 - - example-app@0.2.3 - - @backstage/plugin-auth-backend@0.2.3 - - @backstage/plugin-techdocs-backend@0.2.2 - -## 0.2.2 - -### Patch Changes - -- Updated dependencies [1722cb53c] -- Updated dependencies [1722cb53c] -- Updated dependencies [1722cb53c] -- Updated dependencies [f531d307c] -- Updated dependencies [3efd03c0e] -- Updated dependencies [7b37e6834] -- Updated dependencies [8e2effb53] -- Updated dependencies [d33f5157c] - - @backstage/backend-common@0.3.0 - - @backstage/plugin-app-backend@0.3.0 - - @backstage/plugin-catalog-backend@0.2.1 - - example-app@0.2.2 - - @backstage/plugin-scaffolder-backend@0.3.1 - - @backstage/plugin-auth-backend@0.2.2 - - @backstage/plugin-graphql-backend@0.1.3 - - @backstage/plugin-kubernetes-backend@0.1.3 - - @backstage/plugin-proxy-backend@0.2.1 - - @backstage/plugin-rollbar-backend@0.1.3 - - @backstage/plugin-sentry-backend@0.1.3 - - @backstage/plugin-techdocs-backend@0.2.1 - -## 0.2.1 - -### Patch Changes - -- Updated dependencies [752808090] -- Updated dependencies [462876399] -- Updated dependencies [59166e5ec] -- Updated dependencies [33b7300eb] - - @backstage/plugin-auth-backend@0.2.1 - - @backstage/plugin-scaffolder-backend@0.3.0 - - @backstage/backend-common@0.2.1 - - example-app@0.2.1 - -## 0.2.0 - -### Patch Changes - -- 440a17b39: Bump @backstage/catalog-backend and pass the now required UrlReader interface to the plugin -- 6840a68df: Pass GitHub token into Scaffolder GitHub Preparer -- 8c2b76e45: **BREAKING CHANGE** - - The existing loading of additional config files like `app-config.development.yaml` using APP_ENV or NODE_ENV has been removed. - Instead, the CLI and backend process now accept one or more `--config` flags to load config files. - - Without passing any flags, `app-config.yaml` and, if it exists, `app-config.local.yaml` will be loaded. - If passing any `--config ` flags, only those files will be loaded, **NOT** the default `app-config.yaml` one. - - The old behaviour of for example `APP_ENV=development` can be replicated using the following flags: - - ```bash - --config ../../app-config.yaml --config ../../app-config.development.yaml - ``` - -- 7bbeb049f: Change loadBackendConfig to return the config directly -- Updated dependencies [28edd7d29] -- Updated dependencies [819a70229] -- Updated dependencies [3a4236570] -- Updated dependencies [3e254503d] -- Updated dependencies [6d29605db] -- Updated dependencies [e0be86b6f] -- Updated dependencies [f70a52868] -- Updated dependencies [12b5fe940] -- Updated dependencies [5249594c5] -- Updated dependencies [56e4eb589] -- Updated dependencies [b4e5466e1] -- Updated dependencies [6f1768c0f] -- Updated dependencies [e37c0a005] -- Updated dependencies [3472c8be7] -- Updated dependencies [57d555eb2] -- Updated dependencies [61db1ddc6] -- Updated dependencies [81cb94379] -- Updated dependencies [1687b8fbb] -- Updated dependencies [a768a07fb] -- Updated dependencies [a768a07fb] -- Updated dependencies [f00ca3cb8] -- Updated dependencies [0c370c979] -- Updated dependencies [ce1f55398] -- Updated dependencies [e6b00e3af] -- Updated dependencies [9226c2aaa] -- Updated dependencies [6d97d2d6f] -- Updated dependencies [99710b102] -- Updated dependencies [6579769df] -- Updated dependencies [002860e7a] -- Updated dependencies [5adfc005e] -- Updated dependencies [33454c0f2] -- Updated dependencies [183e2a30d] -- Updated dependencies [948052cbb] -- Updated dependencies [65d722455] -- Updated dependencies [b652bf2cc] -- Updated dependencies [4036ff59d] -- Updated dependencies [991a950e0] -- Updated dependencies [512d70973] -- Updated dependencies [8c2b76e45] -- Updated dependencies [8bdf0bcf5] -- Updated dependencies [c926765a2] -- Updated dependencies [5a920c6e4] -- Updated dependencies [2f62e1804] -- Updated dependencies [440a17b39] -- Updated dependencies [fa56f4615] -- Updated dependencies [8afce088a] -- Updated dependencies [4c4eab81b] -- Updated dependencies [22ff8fba5] -- Updated dependencies [36a71d278] -- Updated dependencies [b3d57961c] -- Updated dependencies [6840a68df] -- Updated dependencies [a5cb46bac] -- Updated dependencies [49d70ccab] -- Updated dependencies [1c8c43756] -- Updated dependencies [26e69ab1a] -- Updated dependencies [5e4551e3a] -- Updated dependencies [e142a2767] -- Updated dependencies [e7f5471fd] -- Updated dependencies [e3d063ffa] -- Updated dependencies [440a17b39] -- Updated dependencies [7bbeb049f] - - @backstage/plugin-app-backend@0.2.0 - - @backstage/plugin-auth-backend@0.2.0 - - @backstage/catalog-model@0.2.0 - - @backstage/plugin-scaffolder-backend@0.2.0 - - @backstage/plugin-techdocs-backend@0.2.0 - - @backstage/plugin-catalog-backend@0.2.0 - - @backstage/plugin-proxy-backend@0.2.0 - - @backstage/backend-common@0.2.0 - - example-app@0.2.0 - - @backstage/plugin-graphql-backend@0.1.2 - - @backstage/plugin-kubernetes-backend@0.1.2 - - @backstage/plugin-rollbar-backend@0.1.2 - - @backstage/plugin-sentry-backend@0.1.2 + - @backstage/backend-app-api@0.1.0-next.0 diff --git a/packages/backend/README.md b/packages/backend/README.md index f71fc9f9d8..46c749fc4b 100644 --- a/packages/backend/README.md +++ b/packages/backend/README.md @@ -1,6 +1,6 @@ # example-backend -This package is an EXAMPLE of a Backstage backend. +This package is an EXAMPLE of a Backstage backend using the [new backend system](https://backstage.io/docs/backend-system/). The main purpose of this package is to provide a test bed for Backstage plugins that have a backend part. Feel free to experiment locally or within your fork @@ -16,22 +16,22 @@ To run the example backend, first go to the project root and run yarn install ``` -You should only need to do this once. +This will install all dependencies for the project. You only need to do this once, unless you make changes to the dependency definitions. -After that, go to the `packages/backend` directory and run +You can then start the backend by running the following command in the repo root: ```bash -yarn start +yarn start-backend ``` If you want to override any configuration locally, for example adding any secrets, -you can do so in `app-config.local.yaml`. +you can do so in `app-config.local.yaml`, next to `app-config.yaml`. The backend starts up on port 7007 per default. ### Debugging -The backend is a node process that can be inspected to allow breakpoints and live debugging. To enable this, pass the `--inspect` flag to [backend:dev](https://backstage.io/docs/local-dev/cli-build-system#backend-development). +The backend is a node process that can be inspected to allow breakpoints and live debugging. To enable this, pass the `--inspect` flag when starting the backend. To debug the backend in [Visual Studio Code](https://code.visualstudio.com/): @@ -51,9 +51,7 @@ in `app-config.yaml` under `catalog.locations`. For local development you can ov ## Authentication -We chose [Passport](http://www.passportjs.org/) as authentication platform due to its comprehensive set of supported authentication [strategies](http://www.passportjs.org/packages/). - -Read more about the [auth-backend](https://github.com/backstage/backstage/blob/master/plugins/auth-backend/README.md) and [how to add a new provider](https://github.com/backstage/backstage/blob/master/docs/auth/add-auth-provider.md) +The example backend has guest access enabled by default. This means you do not need to configure a real authentication provider, but will instead be logged in as a guest user. ## Documentation diff --git a/packages/backend/knip-report.md b/packages/backend/knip-report.md index f57bda79b7..a26b412ee9 100644 --- a/packages/backend/knip-report.md +++ b/packages/backend/knip-report.md @@ -1,27 +1,12 @@ # Knip report -## Unused dependencies (13) +## Unused dependencies (5) -| Name | Location | Severity | -| :------------------------------------------------- | :----------- | :------- | -| @backstage/plugin-scaffolder-backend-module-gitlab | package.json | error | -| @backstage/plugin-scaffolder-backend-module-rails | package.json | error | -| @backstage/plugin-azure-sites-common | package.json | error | -| @backstage/plugin-tech-insights-node | package.json | error | -| azure-devops-node-api | package.json | error | -| pg-connection-string | package.json | error | -| @gitbeaker/node | package.json | error | -| better-sqlite3 | package.json | error | -| @octokit/rest | package.json | error | -| example-app | package.json | error | -| mysql2 | package.json | error | -| luxon | package.json | error | -| pg | package.json | error | - -## Unused devDependencies (2) - -| Name | Location | Severity | -| :------------------------------- | :----------- | :------- | -| @types/express-serve-static-core | package.json | error | -| @types/luxon | package.json | error | +| Name | Location | Severity | +| :----------------------------------------------- | :----------- | :------- | +| @backstage/plugin-catalog-backend-module-openapi | package.json | error | +| @backstage/plugin-search-backend-node | package.json | error | +| @backstage/plugin-permission-common | package.json | error | +| @backstage/plugin-permission-node | package.json | error | +| @backstage/backend-tasks | package.json | error | diff --git a/packages/backend/package.json b/packages/backend/package.json index 378661ae12..999d4dcc46 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.98-next.0", + "version": "0.0.27-next.1", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -18,74 +18,52 @@ "backstage" ], "scripts": { - "start": "backstage-cli package start", "build": "backstage-cli package build", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", "clean": "backstage-cli package clean", - "build-image": "docker build ../.. -f Dockerfile --tag example-backend" + "lint": "backstage-cli package lint", + "start": "backstage-cli package start --require ./src/instrumentation.js", + "test": "backstage-cli package test", + "build-image": "docker build ../.. -f Dockerfile --tag example-backend", + "start:prometheus": "docker run --mount type=bind,source=./prometheus.yml,destination=/etc/prometheus/prometheus.yml --publish published=9090,target=9090,protocol=tcp prom/prometheus" }, "dependencies": { - "@backstage/backend-common": "workspace:^", + "@backstage/backend-defaults": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", - "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", - "@backstage/integration": "workspace:^", "@backstage/plugin-app-backend": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/plugin-auth-backend-module-github-provider": "workspace:^", + "@backstage/plugin-auth-backend-module-guest-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "workspace:^", + "@backstage/plugin-catalog-backend-module-openapi": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^", - "@backstage/plugin-catalog-node": "workspace:^", "@backstage/plugin-devtools-backend": "workspace:^", - "@backstage/plugin-events-backend": "workspace:^", - "@backstage/plugin-events-node": "workspace:^", "@backstage/plugin-kubernetes-backend": "workspace:^", + "@backstage/plugin-notifications-backend": "workspace:^", "@backstage/plugin-permission-backend": "workspace:^", + "@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", "@backstage/plugin-proxy-backend": "workspace:^", "@backstage/plugin-scaffolder-backend": "workspace:^", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^", - "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^", - "@backstage/plugin-scaffolder-backend-module-rails": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-github": "workspace:^", "@backstage/plugin-search-backend": "workspace:^", "@backstage/plugin-search-backend-module-catalog": "workspace:^", - "@backstage/plugin-search-backend-module-elasticsearch": "workspace:^", "@backstage/plugin-search-backend-module-explore": "workspace:^", - "@backstage/plugin-search-backend-module-pg": "workspace:^", "@backstage/plugin-search-backend-module-techdocs": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-signals-backend": "workspace:^", - "@backstage/plugin-signals-node": "workspace:^", "@backstage/plugin-techdocs-backend": "workspace:^", - "@gitbeaker/node": "^35.1.0", - "@octokit/rest": "^19.0.3", - "@opentelemetry/api": "^1.4.1", + "@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/exporter-prometheus": "^0.50.0", - "@opentelemetry/sdk-metrics": "^1.13.0", - "azure-devops-node-api": "^12.0.0", - "better-sqlite3": "^9.0.0", - "dockerode": "^4.0.0", - "example-app": "link:../app", - "express": "^4.17.1", - "express-prom-bundle": "^7.0.0", - "express-promise-router": "^4.1.0", - "luxon": "^3.0.0", - "mysql2": "^3.0.0", - "pg": "^8.11.3", - "pg-connection-string": "^2.3.0", - "prom-client": "^15.0.0", - "winston": "^3.2.1" + "@opentelemetry/sdk-node": "^0.50.0" }, "devDependencies": { - "@backstage/cli": "workspace:^", - "@types/dockerode": "^3.3.0", - "@types/express": "^4.17.6", - "@types/express-serve-static-core": "^4.17.5", - "@types/luxon": "^3.0.0" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/packages/backend-next/src/authModuleGithubProvider.ts b/packages/backend/src/authModuleGithubProvider.ts similarity index 100% rename from packages/backend-next/src/authModuleGithubProvider.ts rename to packages/backend/src/authModuleGithubProvider.ts diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 34ea8b0f6c..a4acd19cf2 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -14,171 +14,38 @@ * limitations under the License. */ -/* - * Hi! - * - * Note that this is an EXAMPLE Backstage backend. Please check the README. - * - * Happy hacking! - */ +import { createBackend } from '@backstage/backend-defaults'; -import Router from 'express-promise-router'; -import { - CacheManager, - createServiceBuilder, - DatabaseManager, - getRootLogger, - HostDiscovery, - loadBackendConfig, - notFoundHandler, - ServerTokenManager, - UrlReaders, - useHotMemoize, -} from '@backstage/backend-common'; -import { TaskScheduler } from '@backstage/backend-tasks'; -import { Config } from '@backstage/config'; -import healthcheck from './plugins/healthcheck'; -import { metricsHandler, metricsInit } from './metrics'; -import auth from './plugins/auth'; -import catalog from './plugins/catalog'; -import events from './plugins/events'; -import kubernetes from './plugins/kubernetes'; -import scaffolder from './plugins/scaffolder'; -import proxy from './plugins/proxy'; -import search from './plugins/search'; -import techdocs from './plugins/techdocs'; -import app from './plugins/app'; -import permission from './plugins/permission'; -import signals from './plugins/signals'; -import devtools from './plugins/devtools'; -import { PluginEnvironment } from './types'; -import { ServerPermissionClient } from '@backstage/plugin-permission-node'; -import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; -import { DefaultEventBroker } from '@backstage/plugin-events-backend'; -import { DefaultEventsService } from '@backstage/plugin-events-node'; -import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'; -import { MeterProvider } from '@opentelemetry/sdk-metrics'; -import { metrics } from '@opentelemetry/api'; -import { DefaultSignalsService } from '@backstage/plugin-signals-node'; +const backend = createBackend(); -// Expose opentelemetry metrics using a Prometheus exporter on -// http://localhost:9464/metrics . See prometheus.yml in packages/backend for -// more information on how to scrape it. -const exporter = new PrometheusExporter(); -const meterProvider = new MeterProvider(); -metrics.setGlobalMeterProvider(meterProvider); -meterProvider.addMetricReader(exporter); +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('./authModuleGithubProvider')); +backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); -function makeCreateEnv(config: Config) { - const root = getRootLogger(); - const reader = UrlReaders.default({ logger: root, config }); - const discovery = HostDiscovery.fromConfig(config); - const tokenManager = ServerTokenManager.fromConfig(config, { logger: root }); - const permissions = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager, - }); - const databaseManager = DatabaseManager.fromConfig(config, { logger: root }); - const cacheManager = CacheManager.fromConfig(config); - const taskScheduler = TaskScheduler.fromConfig(config, { databaseManager }); - const identity = DefaultIdentityClient.create({ - discovery, - }); +backend.add(import('@backstage/plugin-app-backend/alpha')); +backend.add(import('@backstage/plugin-catalog-backend-module-unprocessed')); +backend.add( + import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), +); +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +backend.add(import('@backstage/plugin-devtools-backend')); +backend.add(import('@backstage/plugin-kubernetes-backend/alpha')); +backend.add( + import('@backstage/plugin-permission-backend-module-allow-all-policy'), +); +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(import('@backstage/plugin-techdocs-backend/alpha')); +backend.add(import('@backstage/plugin-signals-backend')); +backend.add(import('@backstage/plugin-notifications-backend')); - const eventsService = DefaultEventsService.create({ logger: root }); - const eventBroker = new DefaultEventBroker( - root.child({ type: 'plugin' }), - eventsService, - ); - const signalsService = DefaultSignalsService.create({ - events: eventsService, - }); - - root.info(`Created UrlReader ${reader}`); - - return (plugin: string): PluginEnvironment => { - const logger = root.child({ type: 'plugin', plugin }); - const database = databaseManager.forPlugin(plugin); - const cache = cacheManager.forPlugin(plugin); - const scheduler = taskScheduler.forPlugin(plugin); - - return { - logger, - cache, - database, - config, - reader, - eventBroker, - events: eventsService, - discovery, - tokenManager, - permissions, - scheduler, - identity, - signals: signalsService, - }; - }; -} - -async function main() { - metricsInit(); - const logger = getRootLogger(); - - logger.info( - `You are running an example backend, which is supposed to be mainly used for contributing back to Backstage. ` + - `Do NOT deploy this to production. Read more here https://backstage.io/docs/getting-started/`, - ); - - const config = await loadBackendConfig({ - argv: process.argv, - logger, - }); - - const createEnv = makeCreateEnv(config); - - const healthcheckEnv = useHotMemoize(module, () => createEnv('healthcheck')); - const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); - const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder')); - const authEnv = useHotMemoize(module, () => createEnv('auth')); - const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); - const searchEnv = useHotMemoize(module, () => createEnv('search')); - const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); - const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes')); - const appEnv = useHotMemoize(module, () => createEnv('app')); - const permissionEnv = useHotMemoize(module, () => createEnv('permission')); - const eventsEnv = useHotMemoize(module, () => createEnv('events')); - const devToolsEnv = useHotMemoize(module, () => createEnv('devtools')); - const signalsEnv = useHotMemoize(module, () => createEnv('signals')); - - const apiRouter = Router(); - apiRouter.use('/catalog', await catalog(catalogEnv)); - apiRouter.use('/events', await events(eventsEnv)); - apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)); - apiRouter.use('/auth', await auth(authEnv)); - apiRouter.use('/search', await search(searchEnv)); - apiRouter.use('/techdocs', await techdocs(techdocsEnv)); - apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv)); - apiRouter.use('/proxy', await proxy(proxyEnv)); - apiRouter.use('/permission', await permission(permissionEnv)); - apiRouter.use('/devtools', await devtools(devToolsEnv)); - apiRouter.use('/signals', await signals(signalsEnv)); - apiRouter.use(notFoundHandler()); - - const service = createServiceBuilder(module) - .loadConfig(config) - .addRouter('', await healthcheck(healthcheckEnv)) - .addRouter('', metricsHandler()) - .addRouter('/api', apiRouter) - .addRouter('', await app(appEnv)); - - await service.start().catch(err => { - logger.error(err); - process.exit(1); - }); -} - -module.hot?.accept(); -main().catch(error => { - console.error('Backend failed to start up', error); - process.exit(1); -}); +backend.start(); diff --git a/packages/backend/src/instrumentation.js b/packages/backend/src/instrumentation.js new file mode 100644 index 0000000000..e3725632c1 --- /dev/null +++ b/packages/backend/src/instrumentation.js @@ -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. + */ + +const { NodeSDK } = require('@opentelemetry/sdk-node'); +const { + getNodeAutoInstrumentations, +} = require('@opentelemetry/auto-instrumentations-node'); +const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); + +// Expose opentelemetry metrics using a Prometheus exporter on +// http://localhost:9464/metrics. See packages/backend/prometheus.yml for +// more information on how to scrape it. +const prometheus = new PrometheusExporter(); + +const sdk = new NodeSDK({ + // traceExporter: ..., + metricReader: prometheus, + instrumentations: [getNodeAutoInstrumentations()], +}); + +sdk.start(); diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index ef3ca6588e..da7b16dce1 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/catalog-client +## 1.6.5 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.5.0 + ## 1.6.5-next.0 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 39d8227fa5..c9e7f25723 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-client", - "version": "1.6.5-next.0", + "version": "1.6.5", "description": "An isomorphic client for the catalog backend", "backstage": { "role": "common-library" diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index c04ac72136..f47465a03e 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/catalog-model +## 1.5.0 + +### Minor Changes + +- 79025f3: Introduce a domain attribute to the domain entity to allow a hierarchy of domains to exist. + ## 1.5.0-next.0 ### Minor Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 5622a20941..5a60531cb2 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-model", - "version": "1.5.0-next.0", + "version": "1.5.0", "description": "Types and validators that help describe the model of a Backstage Catalog", "backstage": { "role": "common-library" diff --git a/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts b/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts index f32236e977..9fe041a839 100644 --- a/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts +++ b/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts @@ -65,11 +65,6 @@ describe('FieldFormatEntityPolicy', () => { await expect(policy.enforce(data)).rejects.toThrow(/kind/); }); - it('handles missing metadata gracefully', async () => { - delete data.medatata; - await expect(policy.enforce(data)).resolves.toBe(data); - }); - it('handles missing spec gracefully', async () => { delete data.spec; await expect(policy.enforce(data)).resolves.toBe(data); diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index dd58feca17..26c9af24ef 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/cli-node +## 0.2.6-next.0 + +### Patch Changes + +- 93be042: Upgraded @yarnpkg/parsers to stable 3.0 +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.5 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 3bd9a98f60..05037a10df 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-node", - "version": "0.2.5", + "version": "0.2.6-next.0", "description": "Node.js library for Backstage CLIs", "backstage": { "role": "node-library" @@ -35,7 +35,7 @@ "@backstage/errors": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", - "@yarnpkg/parsers": "^3.0.0-rc.4", + "@yarnpkg/parsers": "^3.0.0", "fs-extra": "^11.2.0", "semver": "^7.5.3", "zod": "^3.22.4" diff --git a/packages/cli-node/src/roles/types.ts b/packages/cli-node/src/roles/types.ts index a913ff29b6..d6eff04541 100644 --- a/packages/cli-node/src/roles/types.ts +++ b/packages/cli-node/src/roles/types.ts @@ -15,7 +15,7 @@ */ /** - * Backstage package role, see {@link https://backstage.io/docs/local-dev/cli-build-system#package-roles | docs}. + * Backstage package role, see {@link https://backstage.io/docs/tooling/cli/build-system#package-roles | docs}. * * @public */ diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 6c37772f73..3ad3bf3fe5 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/cli +## 0.26.7-next.1 + +### Patch Changes + +- 788eca7: Fix readme for new plugins created using cli +- c00f7ee: Fix issue with `esm` loaded dependencies being different from the `cjs` import for Vite dependencies +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + +## 0.26.6-next.0 + +### Patch Changes + +- 009da47: Fix `versions:check --fix` when `yarn.lock` has multiple joint versions in the same section +- 9ee948a: Bump `esbuild` target for package builds to `ES2022`. +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.11.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.26.5 + +### Patch Changes + +- b8f1fc2: The `build-workspace` command no longer manually runs `yarn postpack`, relying instead on the fact that running `yarn pack` will automatically invoke the `postpack` script. No action is necessary if you are running the latest version of yarn 1, 3, or 4. +- fcd3462: Both the target and types library have been bumped from ES2021 to ES2022 in `@backstage/cli/config/tsconfig.json`. +- 0cc5ed3: Add support for `versions:migrate` to do code changes. Can be skipped with `--no-code-changes` +- f97ad04: Add preserveModules to rollup, which allows better async loading and tree-shaking in webpack +- 2a6f10d: The `versions:bump` command will no longer exit with a non-zero status if the version bump fails due to forbidden duplicate package installations. It will now also provide more information about how to troubleshoot such an error. The set of forbidden duplicates has also been expanded to include all `@backstage/*-app-api` packages. +- c5d7b40: Allow passing a `--require` argument through to the Node process during `package start` +- cc3c518: Fixed an issue causing the `repo fix` command to set an incorrect `workspace` property using Windows +- 812dff0: Add previously-missing semicolon in file templated by `backstage-cli new --select plugin`. +- f185603: Fixed the dynamic import of vite. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.11.0 + +## 0.26.5-next.1 + +### Patch Changes + +- 2a6f10d: The `versions:bump` command will no longer exit with a non-zero status if the version bump fails due to forbidden duplicate package installations. It will now also provide more information about how to troubleshoot such an error. The set of forbidden duplicates has also been expanded to include all `@backstage/*-app-api` packages. +- c5d7b40: Allow passing a `--require` argument through to the Node process during `package start` +- cc3c518: Fixed an issue causing the `repo fix` command to set an incorrect `workspace` property using Windows +- 812dff0: Add previously-missing semicolon in file templated by `backstage-cli new --select plugin`. +- Updated dependencies + - @backstage/integration@1.11.0-next.0 + ## 0.26.5-next.0 ### Patch Changes @@ -1617,9 +1674,7 @@ - 1fe6823bb5: Updated dependency `eslint-plugin-jest` to `^27.0.0`. Note that this major update to the Jest plugin contains some breaking changes. - This means that some of your tests may start seeing some new lint errors. [Read - about them - here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). + This means that some of your tests may start seeing some new lint errors. [Read about them here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). These are mostly possible to fix automatically. You can try to run `yarn backstage-cli repo lint --fix` in your repo root to have most or all of them corrected. @@ -1753,9 +1808,7 @@ - 1fe6823bb5: Updated dependency `eslint-plugin-jest` to `^27.0.0`. Note that this major update to the Jest plugin contains some breaking changes. - This means that some of your tests may start seeing some new lint errors. [Read - about them - here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). + This means that some of your tests may start seeing some new lint errors. [Read about them here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). These are mostly possible to fix automatically. You can try to run `yarn backstage-cli repo lint --fix` in your repo root to have most or all of them corrected. diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 819b1a2261..7b6df4366c 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -280,6 +280,7 @@ Options: --check --inspect [host] --inspect-brk [host] + --require -h, --help ``` diff --git a/packages/cli/package.json b/packages/cli/package.json index ecdfa590d6..e66202b92c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,34 +1,46 @@ { "name": "@backstage/cli", + "version": "0.26.7-next.1", "description": "CLI for developing Backstage plugins and apps", - "version": "0.26.5-next.0", - "publishConfig": { - "access": "public" - }, "backstage": { "role": "cli" }, + "publishConfig": { + "access": "public" + }, + "keywords": [ + "backstage" + ], "homepage": "https://backstage.io", "repository": { "type": "git", "url": "https://github.com/backstage/backstage", "directory": "packages/cli" }, - "keywords": [ - "backstage" - ], "license": "Apache-2.0", "main": "dist/index.cjs.js", - "scripts": { - "build": "backstage-cli package build", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", - "clean": "backstage-cli package clean", - "start": "nodemon --" - }, "bin": { "backstage-cli": "bin/backstage-cli" }, + "files": [ + "asset-types", + "templates", + "config", + "bin", + "dist/**/*.js" + ], + "scripts": { + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "start": "nodemon --", + "test": "backstage-cli package test" + }, + "nodemonConfig": { + "exec": "bin/backstage-cli", + "ext": "ts", + "watch": "./src" + }, "dependencies": { "@backstage/catalog-model": "workspace:^", "@backstage/cli-common": "workspace:^", @@ -67,7 +79,7 @@ "@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/parser": "^6.7.2", "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "^3.0.0-rc.4", + "@yarnpkg/parsers": "^3.0.0", "bfj": "^8.0.0", "buffer": "^6.0.3", "chalk": "^4.0.0", @@ -197,18 +209,6 @@ "optional": true } }, - "files": [ - "asset-types", - "templates", - "config", - "bin", - "dist/**/*.js" - ], - "nodemonConfig": { - "watch": "./src", - "exec": "bin/backstage-cli", - "ext": "ts" - }, "configSchema": { "$schema": "https://backstage.io/schema/config-v1", "title": "@backstage/cli", @@ -248,6 +248,16 @@ "type": "string", "visibility": "frontend", "description": "site for Datadog RUM events" + }, + "sessionSampleRate": { + "type": "number", + "visibility": "frontend", + "description": "sample rate of Datadog RUM events" + }, + "sessionReplaySampleRate": { + "type": "number", + "visibility": "frontend", + "description": "sample rate of session replays based upon already sampled Datadog RUM events" } }, "required": [ diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index fe23926148..3554ddfbef 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -120,6 +120,7 @@ export function registerScriptCommand(program: Command) { '--inspect-brk [host]', 'Enable debugger in Node.js environments, breaking before code starts', ) + .option('--require ', 'Add a --require argument to the node process') .action(lazy(() => import('./start').then(m => m.command))); command diff --git a/packages/cli/src/commands/repo/fix.ts b/packages/cli/src/commands/repo/fix.ts index b975203a73..049f5a8416 100644 --- a/packages/cli/src/commands/repo/fix.ts +++ b/packages/cli/src/commands/repo/fix.ts @@ -22,11 +22,7 @@ import { } from '@backstage/cli-node'; import { OptionValues } from 'commander'; import fs from 'fs-extra'; -import { - resolve as resolvePath, - join as joinPath, - relative as relativePath, -} from 'path'; +import { resolve as resolvePath, posix, relative as relativePath } from 'path'; import { paths } from '../../lib/paths'; /** @@ -205,7 +201,7 @@ export function createRepositoryFieldFixer() { const rootDir = rootRepoField.directory || ''; return (pkg: FixablePackage) => { - const expectedPath = joinPath( + const expectedPath = posix.join( rootDir, relativePath(paths.targetRoot, pkg.dir), ); diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index 427f8b6efb..2f2af95d85 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -27,6 +27,7 @@ export async function command(opts: OptionValues): Promise { checksEnabled: Boolean(opts.check), inspectEnabled: opts.inspect, inspectBrkEnabled: opts.inspectBrk, + require: opts.require, }; switch (role) { diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index 25758a0939..778a31e7e7 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -23,6 +23,7 @@ interface StartBackendOptions { checksEnabled: boolean; inspectEnabled: boolean; inspectBrkEnabled: boolean; + require?: string; } export async function startBackend(options: StartBackendOptions) { @@ -32,6 +33,7 @@ export async function startBackend(options: StartBackendOptions) { checksEnabled: false, // not supported inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled, + require: options.require, }); await waitForExit(); @@ -41,6 +43,7 @@ export async function startBackend(options: StartBackendOptions) { checksEnabled: options.checksEnabled, inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled, + require: options.require, }); await waitForExit(); @@ -70,6 +73,7 @@ export async function startBackendPlugin(options: StartBackendOptions) { checksEnabled: false, // not supported inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled, + require: options.require, }); await waitForExit(); @@ -87,6 +91,7 @@ export async function startBackendPlugin(options: StartBackendOptions) { checksEnabled: options.checksEnabled, inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled, + require: options.require, }); await waitForExit(); @@ -98,6 +103,7 @@ async function cleanDistAndServeBackend(options: { checksEnabled: boolean; inspectEnabled: boolean; inspectBrkEnabled: boolean; + require?: string; }) { // Cleaning dist/ before we start the dev process helps work around an issue // where we end up with the entrypoint executing multiple times, causing diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index c8174639a6..0dfe2f61c3 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -894,30 +894,19 @@ describe('bump', () => { newVersions: [], newRanges: [ { - name: 'first-duplicate', - oldRange: 'first-duplicate', - newRange: 'first-duplicate', - oldVersion: '1.0.0', - newVersion: '2.0.0', - }, - { - name: 'second-duplicate', - oldRange: 'second-duplicate', - newRange: 'second-duplicate', - oldVersion: '1.0.0', - newVersion: '2.0.0', - }, - { - name: 'third-duplicate', - oldRange: 'third-duplicate', - newRange: 'third-duplicate', + 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': lockfileMock, + 'yarn.lock': `${HEADER} +"@backstage/backend-app-api@^1.0.0": + version "1.0.0" +`, 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], @@ -928,16 +917,7 @@ describe('bump', () => { 'package.json': JSON.stringify({ name: 'a', dependencies: { - '@backstage/core': '^1.0.5', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - dependencies: { - '@backstage/core': '^1.0.3', - '@backstage/theme': '^1.0.0', + '@backstage/backend-app-api': '^1.0.0', }, }), }, @@ -952,7 +932,12 @@ describe('bump', () => { res( ctx.status(200), ctx.json({ - packages: [], + packages: [ + { + name: '@backstage/backend-app-api', + version: '2.0.0', + }, + ], }), ), ), @@ -962,24 +947,20 @@ describe('bump', () => { }); expectLogsToMatch(logs, [ 'Using default pattern glob @backstage/*', - 'Checking for updates of @backstage/core', - 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', + 'Checking for updates of @backstage/backend-app-api', + 'Checking for updates of @backstage/backend-app-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', + '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/theme : 1.0.0 ~> 2.0.0', - ' https://github.com/backstage/backstage/blob/master/packages/theme/CHANGELOG.md', + ' @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!', - 'The following packages have duplicates but have been allowed:', - 'first-duplicate, second-duplicate, third-duplicate', + ' ⚠️ 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', ]); }); }); diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index aad5a7831f..1544240704 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -331,24 +331,22 @@ export default async (opts: OptionValues) => { forbiddenDuplicatesFilter(name), ); if (forbiddenNewRanges.length > 0) { - throw new Error( - `Version bump failed for ${forbiddenNewRanges - .map(i => i.name) - .join(', ')}`, - ); - } - - const allowedDuplicates = result.newRanges.filter( - ({ name }) => !forbiddenDuplicatesFilter(name), - ); - - if (allowedDuplicates.length > 0) { + console.log(chalk.yellow(' ⚠️ Warning! ⚠️')); + console.log(); console.log( chalk.yellow( - 'The following packages have duplicates but have been allowed:', + ' The below package(s) have incompatible duplicate installations, likely due to a bad dependency in a plugin.', ), ); - console.log(chalk.yellow(allowedDuplicates.map(i => i.name).join(', '))); + 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}`)); + } } }; diff --git a/packages/cli/src/commands/versions/lint.ts b/packages/cli/src/commands/versions/lint.ts index 9466fd0ab7..bfb2a752a0 100644 --- a/packages/cli/src/commands/versions/lint.ts +++ b/packages/cli/src/commands/versions/lint.ts @@ -27,10 +27,7 @@ export const includedFilter = (name: string) => INCLUDED.some(pattern => pattern.test(name)); // Packages that are not allowed to have any duplicates -const FORBID_DUPLICATES = [ - /^@backstage\/core-app-api$/, - /^@backstage\/plugin-/, -]; +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 diff --git a/packages/cli/src/lib/builder/config.ts b/packages/cli/src/lib/builder/config.ts index 6fd92101f6..8beb2cbb1e 100644 --- a/packages/cli/src/lib/builder/config.ts +++ b/packages/cli/src/lib/builder/config.ts @@ -151,7 +151,7 @@ export async function makeRollupConfigs( template: svgrTemplate, }), esbuild({ - target: 'es2019', + target: 'ES2022', minify: options.minify, }), ], diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index dc90bed1e7..53db7f3597 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -276,6 +276,9 @@ export async function createBackendConfig( : '--inspect-brk'; runScriptNodeArgs.push(inspect); } + if (options.require) { + runScriptNodeArgs.push(`--require=${options.require}`); + } return { mode: isDev ? 'development' : 'production', diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 2b7311a34c..1da15cd37e 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -165,12 +165,12 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be }); if (process.env.EXPERIMENTAL_VITE) { - const { default: vite } = await import('vite'); - const { default: viteReact } = await import('@vitejs/plugin-react'); - const { nodePolyfills: viteNodePolyfills } = await import( - 'vite-plugin-node-polyfills' - ); - const { createHtmlPlugin: viteHtml } = await import('vite-plugin-html'); + const vite = require('vite'); + const { default: viteReact } = require('@vitejs/plugin-react'); + const { + nodePolyfills: viteNodePolyfills, + } = require('vite-plugin-node-polyfills'); + const { createHtmlPlugin: viteHtml } = require('vite-plugin-html'); viteServer = await vite.createServer({ define: { global: 'window', diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 8fe25e91c5..85a641465f 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -54,10 +54,12 @@ export type BackendBundlingOptions = { parallelism?: number; inspectEnabled: boolean; inspectBrkEnabled: boolean; + require?: string; }; export type BackendServeOptions = BundlingPathsOptions & { checksEnabled: boolean; inspectEnabled: boolean; inspectBrkEnabled: boolean; + require?: string; }; diff --git a/packages/cli/src/lib/experimental/startBackendExperimental.ts b/packages/cli/src/lib/experimental/startBackendExperimental.ts index 19f71aa993..bd4bb94b17 100644 --- a/packages/cli/src/lib/experimental/startBackendExperimental.ts +++ b/packages/cli/src/lib/experimental/startBackendExperimental.ts @@ -96,6 +96,9 @@ export async function startBackendExperimental(options: BackendServeOptions) { : '--inspect-brk'; optionArgs.push(inspect); } + if (options.require) { + optionArgs.push(`--require=${options.require}`); + } const userArgs = process.argv .slice(['node', 'backstage-cli', 'package', 'start'].length) diff --git a/packages/cli/src/lib/packager/createDistWorkspace.ts b/packages/cli/src/lib/packager/createDistWorkspace.ts index 7d4c9d4c6d..b966e23a85 100644 --- a/packages/cli/src/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/lib/packager/createDistWorkspace.ts @@ -309,10 +309,6 @@ async function moveToDistWorkspace( await run('yarn', ['pack', '--filename', archivePath], { cwd: target.dir, }); - // TODO(Rugvip): yarn pack doesn't call postpack, once the bug is fixed this can be removed - if (target.packageJson?.scripts?.postpack) { - await run('yarn', ['postpack'], { cwd: target.dir }); - } const outputDir = relativePath(paths.targetRoot, target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); diff --git a/packages/cli/src/lib/versioning/Lockfile.ts b/packages/cli/src/lib/versioning/Lockfile.ts index 50d0a77cfd..6af115a4da 100644 --- a/packages/cli/src/lib/versioning/Lockfile.ts +++ b/packages/cli/src/lib/versioning/Lockfile.ts @@ -98,6 +98,24 @@ export class Lockfile { return Lockfile.parse(lockfileContents); } + static #getRangesFromDataKey(key: string): string[] { + const [, name, ranges] = key.match(ENTRY_PATTERN) ?? []; + if (!name) { + throw new Error(`Failed to parse yarn.lock entry '${key}'`); + } + + return ranges.split(/\s*,\s*/).map(rangePart => { + let range = rangePart; + if (range.startsWith(`${name}@`)) { + range = range.slice(`${name}@`.length); + } + if (range.startsWith('npm:')) { + range = range.slice('npm:'.length); + } + return range; + }); + } + static parse(content: string) { const legacy = LEGACY_REGEX.test(content); @@ -113,7 +131,7 @@ export class Lockfile { for (const [key, value] of Object.entries(data)) { if (SPECIAL_OBJECT_KEYS.includes(key)) continue; - const [, name, ranges] = ENTRY_PATTERN.exec(key) ?? []; + const [, name] = ENTRY_PATTERN.exec(key) ?? []; if (!name) { throw new Error(`Failed to parse yarn.lock entry '${key}'`); } @@ -123,13 +141,8 @@ export class Lockfile { queries = []; packages.set(name, queries); } - for (let range of ranges.split(/\s*,\s*/)) { - if (range.startsWith(`${name}@`)) { - range = range.slice(`${name}@`.length); - } - if (range.startsWith('npm:')) { - range = range.slice('npm:'.length); - } + const ranges = Lockfile.#getRangesFromDataKey(key); + for (const range of ranges) { queries.push({ range, version: value.version, dataKey: key }); } } @@ -276,9 +289,34 @@ export class Lockfile { } remove(name: string, range: string): boolean { - const query = `${name}@${range}`; + const simpleQuery = `${name}@${range}`; + const query = this.getEntryOf(name, range); + const existed = Boolean(this.data[query]); - delete this.data[query]; + + if (simpleQuery === query) { + // Single-versioned entry, just delete + delete this.data[query]; + } else { + // Remove this version from the entry key. This modifies the key, so the + // package queries' needs to be updated too. + const newRanges = Lockfile.#getRangesFromDataKey(query).filter( + q => q !== simpleQuery, + ); + const newQuery = newRanges.join(', '); + + // Replace the entry with a new one without this particular range + const entry = this.data[query]; + delete this.data[query]; + this.data[newQuery] = entry; + + // Fix all package queries pointing to the old query + this.packages.get(name)?.forEach(q => { + if (q.dataKey === query) { + q.dataKey = newQuery; + } + }); + } const newEntries = this.packages.get(name)?.filter(e => e.range !== range); if (newEntries) { @@ -288,19 +326,35 @@ export class Lockfile { return existed; } + getEntryOf(name: string, range: string) { + const query = this.packages.get(name)?.find(q => q.range === range); + if (!query) { + throw new Error(`No entry data for ${name}@${range}`); + } + + return query.dataKey; + } + /** Modifies the lockfile by bumping packages to the suggested versions */ replaceVersions(results: AnalyzeResultNewVersion[]) { + // When replacing versions, we might replace the same version multiple times, + // as a query may contain multiple versions. This keeps the original version, + // to ensure we don't make mistakes. + const oldVersions = Object.fromEntries( + Object.entries(this.data).map(([key, val]) => [key, val.version]), + ); + for (const { name, range, oldVersion, newVersion } of results) { - const query = `${name}@${range}`; + const query = this.getEntryOf(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) { + if (oldVersions[query] !== oldVersion) { throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, + `Expected existing version data for ${query} to be ${oldVersion}, was ${oldVersions[query]}`, ); } diff --git a/packages/cli/templates/default-backend-plugin/README.md.hbs b/packages/cli/templates/default-backend-plugin/README.md.hbs index e95c626167..366ed27104 100644 --- a/packages/cli/templates/default-backend-plugin/README.md.hbs +++ b/packages/cli/templates/default-backend-plugin/README.md.hbs @@ -7,7 +7,7 @@ _This plugin was created through the Backstage CLI_ ## 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 [/{{pluginVar}}/health](http://localhost:7007/api/{{pluginVar}}/health). +start` in the root directory, and then navigating to [/{{id}}/health](http://localhost:7007/api/{{id}}/health). 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. diff --git a/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx.hbs b/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx.hbs index 1fe424ab9b..1e746ff39a 100644 --- a/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx.hbs +++ b/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx.hbs @@ -8,7 +8,7 @@ describe('ExampleFetchComponent', () => { // Wait for the table to render const table = await screen.findByRole('table'); - const nationality = screen.getAllByText('GB') + const nationality = screen.getAllByText('GB'); // Assert that the table contains the expected user data expect(table).toBeInTheDocument(); expect(screen.getByAltText('Carolyn')).toBeInTheDocument(); diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index c13bf1613e..f171c222b7 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/core-app-api +## 1.12.5 + +### Patch Changes + +- 1bed9a3: The Backstage identity session expiration check will no longer fall back to using the provider expiration. This was introduced to smooth out the rollout of Backstage release 1.18, and is no longer needed. + ## 1.12.4 ### Patch Changes @@ -539,8 +545,7 @@ This change makes the dependence explicit, and removes the burden on OAuth2-based providers which require an ID token (e.g. this is done by various - default [auth - handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add + default [auth handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add `openid` to their default scopes. _That_ could carry another indirect benefit: by removing `openid` from the default scopes for a provider, grants for resource-specific access tokens can avoid requesting excess ID token-related @@ -568,8 +573,7 @@ This change makes the dependence explicit, and removes the burden on OAuth2-based providers which require an ID token (e.g. this is done by various - default [auth - handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add + default [auth handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add `openid` to their default scopes. _That_ could carry another indirect benefit: by removing `openid` from the default scopes for a provider, grants for resource-specific access tokens can avoid requesting excess ID token-related diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index b61a860298..0a74dac3f8 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.12.4", + "version": "1.12.5", "publishConfig": { "access": "public" }, diff --git a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts index 6be7cfc89d..dbad031652 100644 --- a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts +++ b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts @@ -116,16 +116,11 @@ export default class OAuth2 }, }; if (backstageIdentity) { - // TODO(Rugvip): This fallback can be removed a few releases after 1.18. It's there to avoid - // breaking deployments that update their frontend before updating their backend. - const expInSec = - backstageIdentity.expiresInSeconds ?? - res.providerInfo.expiresInSeconds; session.backstageIdentity = { token: backstageIdentity.token, identity: backstageIdentity.identity, - expiresAt: expInSec - ? new Date(Date.now() + expInSec * 1000) + expiresAt: backstageIdentity.expiresInSeconds + ? new Date(Date.now() + backstageIdentity.expiresInSeconds * 1000) : undefined, }; } diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 59b53bf6c5..1345ccb13e 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -20,7 +20,7 @@ import { renderWithEffects, withLogCollector, } from '@backstage/test-utils'; -import { render, screen, waitFor } from '@testing-library/react'; +import { render, screen, waitFor, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React, { PropsWithChildren, ReactNode } from 'react'; import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; @@ -874,7 +874,9 @@ describe('Integration Test', () => { ); await renderWithEffects(); - await userEvent.click(screen.getByText('Sign Out')); + await act(async () => { + await userEvent.click(screen.getByText('Sign Out')); + }); await waitFor(() => expect(fetchApiMock.fetch).toHaveBeenCalledWith( diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 29ebd0cc2b..c6869bee6d 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/core-compat-api +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/version-bridge@1.0.8 + +## 0.2.5 + +### Patch Changes + +- 5d99272: Update local development dependencies. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.5 + +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.5-next.1 + ## 0.2.5-next.0 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index a7bab7b52f..cf84e36b5c 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.5-next.0", + "version": "0.2.6-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/core-components/.eslintrc.js b/packages/core-components/.eslintrc.js index 505ea657a2..f5ec47b36a 100644 --- a/packages/core-components/.eslintrc.js +++ b/packages/core-components/.eslintrc.js @@ -4,6 +4,10 @@ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { '@backstage/no-top-level-material-ui-4-imports': 'error', }, restrictedImports: [ + { + name: '@backstage/core-components', + message: "To avoid circular dependencies, use relative paths to import '@backstage/core-components' from its subdirectories." + }, { name: '@material-ui/core', message: "Please import '@material-ui/core/...' instead.", diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 4e8f90b441..8b2e59d15f 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/core-components +## 0.14.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/version-bridge@1.0.8 + +## 0.14.7 + +### Patch Changes + +- e42779e: Properly log the `errorInfo` in `ErrorBoundary` +- 5223c4c: Fixed an internal circular import that broke Jest mocks. +- 71e4229: Added optional `initialShowDropDown` prop to `SidebarSubmenuItem` to internally manage the initial display state of the dropdown items. +- a2ee4df: Add `alignGauge` prop to the `GaugeCard`, and a small size version. When `alignGauge` is `'bottom'` the gauge will vertically align the gauge in the cards, even when the card titles span across multiple lines. + Add `alignContent` prop to the `InfoCard`, defaulting to `'normal'` with the option of `'bottom'` which vertically aligns the content to the bottom of the card. +- 5b7b49b: The `SignInPage` guest provider will now fall back to legacy guest auth if the backend request fails, allowing guest auth without a running backend. +- 359376a: Removing react-text-truncate with css styles. +- Updated dependencies + - @backstage/theme@0.5.4 + +## 0.14.7-next.2 + +### Patch Changes + +- a2ee4df: Add `alignGauge` prop to the `GaugeCard`, and a small size version. When `alignGauge` is `'bottom'` the gauge will vertically align the gauge in the cards, even when the card titles span across multiple lines. + Add `alignContent` prop to the `InfoCard`, defaulting to `'normal'` with the option of `'bottom'` which vertically aligns the content to the bottom of the card. + +## 0.14.6-next.1 + +### Patch Changes + +- 5223c4c: Fixed an internal circular import that broke Jest mocks. +- 5b7b49b: The `SignInPage` guest provider will now fall back to legacy guest auth if the backend request fails, allowing guest auth without a running backend. + ## 0.14.5-next.0 ### Patch Changes diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 2a146e70e0..0f71bcb004 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -47,7 +47,6 @@ import { StyledComponentProps } from '@material-ui/core/styles/withStyles'; import { StyleRules } from '@material-ui/styles'; import { StyleRules as StyleRules_2 } from '@material-ui/core/styles/withStyles'; import { TabProps } from '@material-ui/core/Tab'; -import { TextTruncateProps } from 'react-text-truncate'; import { Theme } from '@material-ui/core/styles'; import { TooltipProps } from '@material-ui/core/Tooltip'; import { WithStyles } from '@material-ui/core/styles'; @@ -448,6 +447,7 @@ export type GaugeProps = { inverse?: boolean; unit?: string; max?: number; + size?: 'normal' | 'small'; description?: ReactNode; getColor?: GaugePropsGetColor; }; diff --git a/packages/core-components/package.json b/packages/core-components/package.json index df637fa3a8..cdcdbb67a0 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,31 +1,32 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.14.5-next.0", + "version": "0.14.8-next.0", "publishConfig": { "access": "public" }, "backstage": { "role": "web-library" }, + "keywords": [ + "backstage" + ], "homepage": "https://backstage.io", "repository": { "type": "git", "url": "https://github.com/backstage/backstage", "directory": "packages/core-components" }, - "keywords": [ - "backstage" - ], "license": "Apache-2.0", - "main": "src/index.ts", - "types": "src/index.ts", + "sideEffects": false, "exports": { ".": "./src/index.ts", "./alpha": "./src/alpha.ts", "./testUtils": "./src/testUtils.ts", "./package.json": "./package.json" }, + "main": "src/index.ts", + "types": "src/index.ts", "typesVersions": { "*": { "alpha": [ @@ -39,15 +40,18 @@ ] } }, - "sideEffects": false, + "files": [ + "dist", + "config.d.ts" + ], "scripts": { "build": "backstage-cli package build", + "clean": "backstage-cli package clean", "lint": "backstage-cli package lint", - "test": "backstage-cli package test", "prepack": "backstage-cli package prepack", "postpack": "backstage-cli package postpack", - "clean": "backstage-cli package clean", - "start": "backstage-cli package start" + "start": "backstage-cli package start", + "test": "backstage-cli package test" }, "dependencies": { "@backstage/config": "workspace:^", @@ -63,7 +67,6 @@ "@react-hookz/web": "^24.0.0", "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0", "@types/react-sparklines": "^1.7.0", - "@types/react-text-truncate": "^0.14.0", "ansi-regex": "^6.0.1", "classnames": "^2.2.6", "d3-selection": "^3.0.0", @@ -82,7 +85,6 @@ "react-markdown": "^8.0.0", "react-sparklines": "^1.7.0", "react-syntax-highlighter": "^15.4.5", - "react-text-truncate": "^0.19.0", "react-use": "^17.3.2", "react-virtualized-auto-sizer": "^1.0.11", "react-window": "^1.8.6", @@ -90,11 +92,6 @@ "zen-observable": "^0.10.0", "zod": "^3.22.4" }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-router-dom": "6.0.0-beta.0 || ^6.3.0" - }, "devDependencies": { "@backstage/app-defaults": "workspace:^", "@backstage/cli": "workspace:^", @@ -120,9 +117,10 @@ "history": "^5.0.0", "msw": "^1.0.0" }, - "files": [ - "dist", - "config.d.ts" - ], + "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" + }, "configSchema": "config.d.ts" } diff --git a/packages/core-components/src/components/HeaderIconLinkRow/HeaderIconLinkRow.stories.tsx b/packages/core-components/src/components/HeaderIconLinkRow/HeaderIconLinkRow.stories.tsx new file mode 100644 index 0000000000..e472ab5599 --- /dev/null +++ b/packages/core-components/src/components/HeaderIconLinkRow/HeaderIconLinkRow.stories.tsx @@ -0,0 +1,48 @@ +/* + * 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 { HeaderIconLinkRow } from '../HeaderIconLinkRow'; +import { IconLinkVerticalProps } from './IconLinkVertical'; + +type Props = { + links: IconLinkVerticalProps[]; +}; + +export default { + title: 'Data Display/HeaderIconLinkRow', + component: HeaderIconLinkRow, +}; + +export const Default = (args: Props) => ; +Default.args = { + links: [ + { + color: 'primary', + disabled: false, + href: 'https://google.com', + label: 'primary', + title: 'title', + }, + { + color: 'secondary', + disabled: false, + href: 'https://google.com', + label: 'secondary', + title: 'title-2', + }, + ], +}; diff --git a/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx b/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx index da489725e4..4b5b0f4bde 100644 --- a/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx +++ b/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx @@ -16,15 +16,13 @@ import { makeStyles } from '@material-ui/core/styles'; import Tooltip, { TooltipProps } from '@material-ui/core/Tooltip'; -import React, { useState } from 'react'; -import TextTruncate, { TextTruncateProps } from 'react-text-truncate'; -import { useIsMounted } from '@react-hookz/web'; +import React from 'react'; +import Typography from '@material-ui/core/Typography'; type Props = { - text: TextTruncateProps['text']; - line?: TextTruncateProps['line']; - element?: TextTruncateProps['element']; + text?: string | undefined; title?: TooltipProps['title']; + line?: number | undefined; placement?: TooltipProps['placement']; }; @@ -35,33 +33,26 @@ const useStyles = makeStyles( container: { overflow: 'visible !important', }, + typo: { + overflow: 'hidden', + textOverflow: 'ellipsis', + display: '-webkit-box', + '-webkit-line-clamp': ({ line }: Props) => line || 1, + '-webkit-box-orient': 'vertical', + }, }, { name: 'BackstageOverflowTooltip' }, ); export function OverflowTooltip(props: Props) { - const [hover, setHover] = useState(false); - const isMounted = useIsMounted(); - const classes = useStyles(); - - const handleToggled = (truncated: boolean) => { - if (isMounted()) { - setHover(truncated); - } - }; + const classes = useStyles(props); return ( - + {props.text} ); } diff --git a/packages/core-components/src/components/ProgressBars/Gauge.tsx b/packages/core-components/src/components/ProgressBars/Gauge.tsx index 088e369e62..e72172fd59 100644 --- a/packages/core-components/src/components/ProgressBars/Gauge.tsx +++ b/packages/core-components/src/components/ProgressBars/Gauge.tsx @@ -19,6 +19,7 @@ import { makeStyles, useTheme } from '@material-ui/core/styles'; import { Circle } from 'rc-progress'; import React, { ReactNode, useEffect, useState } from 'react'; import Box from '@material-ui/core/Box'; +import classNames from 'classnames'; /** @public */ export type GaugeClassKey = @@ -43,6 +44,9 @@ const useStyles = makeStyles( fontWeight: theme.typography.fontWeightBold, color: theme.palette.textContrast, }, + overlaySmall: { + fontSize: theme.typography.pxToRem(25), + }, description: { fontSize: '100%', top: '50%', @@ -68,6 +72,7 @@ export type GaugeProps = { inverse?: boolean; unit?: string; max?: number; + size?: 'normal' | 'small'; description?: ReactNode; getColor?: GaugePropsGetColor; }; @@ -121,7 +126,7 @@ export const getProgressColor: GaugePropsGetColor = ({ export function Gauge(props: GaugeProps) { const [hoverRef, setHoverRef] = useState(null); - const { getColor = getProgressColor } = props; + const { getColor = getProgressColor, size = 'normal' } = props; const classes = useStyles(props); const { palette } = useTheme(); const { value, fractional, inverse, unit, max, description } = { @@ -165,7 +170,11 @@ export function Gauge(props: GaugeProps) { {description && isHovering ? ( {description} ) : ( - + {isNaN(value) ? 'N/A' : `${asActual}${unit}`} )} diff --git a/packages/core-components/src/components/ProgressBars/GaugeCard.stories.tsx b/packages/core-components/src/components/ProgressBars/GaugeCard.stories.tsx index a0b6faea60..f7e2eb69c6 100644 --- a/packages/core-components/src/components/ProgressBars/GaugeCard.stories.tsx +++ b/packages/core-components/src/components/ProgressBars/GaugeCard.stories.tsx @@ -175,6 +175,91 @@ export const InfoMessage = () => ( ); +export const AlignedBottom = () => ( + + + + + + + + + + + + + + +); + +export const Small = () => ( + + + + + + + + + + + + + + +); + export const HoverMessage = () => ( diff --git a/packages/core-components/src/components/ProgressBars/GaugeCard.tsx b/packages/core-components/src/components/ProgressBars/GaugeCard.tsx index 3442395380..9f6de8eafe 100644 --- a/packages/core-components/src/components/ProgressBars/GaugeCard.tsx +++ b/packages/core-components/src/components/ProgressBars/GaugeCard.tsx @@ -27,6 +27,8 @@ type Props = { variant?: InfoCardVariants; /** Progress in % specified as decimal, e.g. "0.23" */ progress: number; + alignGauge?: 'normal' | 'bottom'; + size?: 'normal' | 'small'; description?: ReactNode; icon?: ReactNode; inverse?: boolean; @@ -43,6 +45,10 @@ const useStyles = makeStyles( height: '100%', width: 250, }, + rootSmall: { + height: '100%', + width: 160, + }, }, { name: 'BackstageGaugeCard' }, ); @@ -64,6 +70,8 @@ export function GaugeCard(props: Props) { description, icon, variant, + alignGauge = 'normal', + size = 'normal', getColor, } = props; @@ -75,15 +83,22 @@ export function GaugeCard(props: Props) { }; return ( - + - + ); diff --git a/packages/core-components/src/components/ResponseErrorPanel/ResponseErrorPanel.stories.tsx b/packages/core-components/src/components/ResponseErrorPanel/ResponseErrorPanel.stories.tsx new file mode 100644 index 0000000000..8d03e7359f --- /dev/null +++ b/packages/core-components/src/components/ResponseErrorPanel/ResponseErrorPanel.stories.tsx @@ -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. + */ + +import React from 'react'; +import { ResponseErrorPanel } from '../ResponseErrorPanel'; +import { ErrorPanelProps } from '../ErrorPanel'; + +export default { + title: 'Data Display/ResponseErrorPanel', + component: ResponseErrorPanel, +}; + +export const Default = (args: ErrorPanelProps) => ( + +); +Default.args = { + error: new Error('Error message from error object'), + defaultExpanded: false, +}; + +export const WithTitle = (args: ErrorPanelProps) => ( + +); +WithTitle.args = { + error: new Error('test'), + defaultExpanded: false, + title: 'Title prop is passed', +}; diff --git a/packages/core-components/src/layout/BottomLink/BottomLink.stories.tsx b/packages/core-components/src/layout/BottomLink/BottomLink.stories.tsx new file mode 100644 index 0000000000..e05af86993 --- /dev/null +++ b/packages/core-components/src/layout/BottomLink/BottomLink.stories.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 { BottomLink } from '../BottomLink'; + +export default { + title: 'Layout/BottomLink', + component: BottomLink, +}; + +export const Default = (args: { link: string; title: string }) => ( + +); +Default.args = { + link: 'https://google.com', + title: 'This is bottom link', +}; diff --git a/packages/core-components/src/layout/Content/Content.stories.tsx b/packages/core-components/src/layout/Content/Content.stories.tsx new file mode 100644 index 0000000000..fcf8858adc --- /dev/null +++ b/packages/core-components/src/layout/Content/Content.stories.tsx @@ -0,0 +1,50 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Content } from './Content'; + +export default { + title: 'Layout/Content', + component: Content, +}; + +type Props = { + stretch?: boolean; + noPadding?: boolean; + className?: string; +}; + +export const Default = (args: Props) => ( + +
This is child of content component
+
+); + +Default.args = { + stretch: false, + noPadding: false, +}; + +export const WithNoPadding = (args: Props) => ( + +
This is child of content component
+
+); + +WithNoPadding.args = { + stretch: true, + noPadding: true, +}; diff --git a/packages/core-components/src/layout/ContentHeader/ContentHeader.stories.tsx b/packages/core-components/src/layout/ContentHeader/ContentHeader.stories.tsx new file mode 100644 index 0000000000..27df00e72c --- /dev/null +++ b/packages/core-components/src/layout/ContentHeader/ContentHeader.stories.tsx @@ -0,0 +1,73 @@ +/* + * 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, { ReactNode } from 'react'; +import { ContentHeader } from '../ContentHeader'; + +export default { + title: 'Layout/ContentHeader', + component: ContentHeader, +}; + +type ContentHeaderProps = { + title?: string; + titleComponent?: ReactNode; + description?: string; + textAlign?: 'left' | 'right' | 'center'; +}; + +export const Default = (args: ContentHeaderProps) => ( + +
Child of Content Header
+
+); +Default.args = { + title: 'This is Content Header default aligned', + description: 'This is description', +}; + +export const Left = (args: ContentHeaderProps) => ( + +
Child of Content Header
+
+); +Left.args = { + title: 'This is Content Header left aligned', + description: 'This is description', + textAlign: 'left', +}; + +export const Right = (args: ContentHeaderProps) => ( + +
Child of Content Header
+
+); +Right.args = { + title: 'This is Content Header right aligned', + description: 'This is description', + textAlign: 'right', +}; + +export const Center = (args: ContentHeaderProps) => ( + +
Child of Content Header
+
+); +Center.args = { + title: 'This is Content Header center aligned', + description: 'This is description', + textAlign: 'center', +}; diff --git a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx index 8f746882a1..b3a5d1db90 100644 --- a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx +++ b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx @@ -79,7 +79,7 @@ export const ErrorBoundary: ComponentClass< componentDidCatch(error: Error, errorInfo: ErrorInfo) { // eslint-disable-next-line no-console - console.error(`ErrorBoundary, error: ${error}, info: ${errorInfo}`); + console.error(`ErrorBoundary, error: ${error}`, { error, errorInfo }); this.setState({ error, errorInfo }); } diff --git a/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.stories.tsx b/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.stories.tsx new file mode 100644 index 0000000000..dc50456f7e --- /dev/null +++ b/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.stories.tsx @@ -0,0 +1,45 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { HeaderActionMenu, HeaderActionMenuProps } from './HeaderActionMenu'; + +export default { + title: 'Layout/HeaderActionMenu', + component: HeaderActionMenu, +}; + +export const Default = (args: HeaderActionMenuProps) => ( + +); +Default.args = { + actionItems: [ + { + label: 'Item 1', + secondaryLabel: 'Item 1 secondary label', + disabled: false, + }, + { + label: 'Item 2', + secondaryLabel: 'Item 2 secondary label', + disabled: true, + }, + { + label: 'Item 3', + secondaryLabel: 'Item 3 secondary label', + disabled: true, + }, + ], +}; diff --git a/packages/core-components/src/layout/HeaderLabel/HeaderLabel.stories.tsx b/packages/core-components/src/layout/HeaderLabel/HeaderLabel.stories.tsx new file mode 100644 index 0000000000..58566a27d2 --- /dev/null +++ b/packages/core-components/src/layout/HeaderLabel/HeaderLabel.stories.tsx @@ -0,0 +1,35 @@ +/* + * 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 { HeaderLabel } from './HeaderLabel'; + +export default { + title: 'Layout/HeaderLabel', + component: HeaderLabel, +}; + +type HeaderLabelProps = { + label: string; + value?: string; + url?: string; +}; + +export const Default = (args: HeaderLabelProps) => ; +Default.args = { + label: 'This is label', + value: 'This is value', + url: 'https://backstage.io', +}; diff --git a/packages/core-components/src/layout/InfoCard/InfoCard.tsx b/packages/core-components/src/layout/InfoCard/InfoCard.tsx index c80e71b609..a08a816c2e 100644 --- a/packages/core-components/src/layout/InfoCard/InfoCard.tsx +++ b/packages/core-components/src/layout/InfoCard/InfoCard.tsx @@ -43,6 +43,10 @@ const useStyles = makeStyles( paddingBottom: 0, }, }, + contentAlignBottom: { + display: 'flex', + alignItems: 'self-end', + }, header: { padding: theme.spacing(2, 2, 2, 2.5), }, @@ -138,6 +142,7 @@ export type Props = { slackChannel?: string; errorBoundaryProps?: ErrorBoundaryProps; variant?: InfoCardVariants; + alignContent?: 'normal' | 'bottom'; children?: ReactNode; headerStyle?: object; headerProps?: CardHeaderProps; @@ -150,6 +155,7 @@ export type Props = { className?: string; noPadding?: boolean; titleTypographyProps?: object; + subheaderTypographyProps?: object; }; /** @@ -167,6 +173,7 @@ export function InfoCard(props: Props): JSX.Element { slackChannel, errorBoundaryProps, variant, + alignContent = 'normal', children, headerStyle, headerProps, @@ -179,6 +186,7 @@ export function InfoCard(props: Props): JSX.Element { className, noPadding, titleTypographyProps, + subheaderTypographyProps, } = props; const classes = useStyles(); /** @@ -209,10 +217,7 @@ export function InfoCard(props: Props): JSX.Element { } return ( -
+
{subheader &&
{subheader}
} {icon}
@@ -228,7 +233,7 @@ export function InfoCard(props: Props): JSX.Element { {title && ( )} @@ -250,6 +256,7 @@ export function InfoCard(props: Props): JSX.Element { diff --git a/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx b/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx index 707d528867..329fb62129 100644 --- a/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx +++ b/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx @@ -104,7 +104,7 @@ describe('', () => { const rendered = render( wrapInTestApp( - + Test Content 1 diff --git a/packages/core-components/src/setupTests.ts b/packages/core-components/src/setupTests.ts index 963c0f188b..dae4360fd3 100644 --- a/packages/core-components/src/setupTests.ts +++ b/packages/core-components/src/setupTests.ts @@ -15,3 +15,18 @@ */ import '@testing-library/jest-dom'; + +// eslint-disable-next-line no-console +const originalConsoleWarn = console.warn; +// eslint-disable-next-line no-console +console.warn = (...args: any[]) => { + const message = args[0]; + if ( + typeof message === 'string' && + (message.includes('CSSOM.parse is not a function') || + message.includes('[JSS]')) + ) { + return; + } + originalConsoleWarn(...args); +}; diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 2706fc14b5..67560bf6c3 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/create-app +## 0.5.16-next.1 + +### Patch Changes + +- Bumped create-app version. + +## 0.5.16-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.15 + +### Patch Changes + +- c066c88: Removed `packages/backend/src/types.ts` from the template as it is unused. It was mistakenly left in after moving the template to the new backend system. +- 5d99272: Update local development dependencies. +- 0478509: Bumped create-app version. +- d85dd88: Bumped create-app version. +- 8105aad: Removed the Tech Radar and GitHub Actions plugins from the template, which have been moved to the community plugins repository. + +## 0.5.15-next.2 + +### Patch Changes + +- Bumped create-app version. + +## 0.5.15-next.1 + +### Patch Changes + +- Bumped create-app version. + ## 0.5.15-next.0 ### Patch Changes @@ -1122,8 +1158,7 @@ Migrating to the stable version of `react-router` is optional for the time being. But if you want to do the same for your existing repository, please - follow [this - guide](https://backstage.io/docs/tutorials/react-router-stable-migration). + follow [this guide](https://backstage.io/docs/tutorials/react-router-stable-migration). - e05e0f021b: Update versions of packages used in the create-app template, to match those in the main repo - 01dff06be4: Leverage cache mounts in Dockerfile during `yarn install ...` and `apt-get ...` commands to speed up repeated builds. @@ -1170,8 +1205,7 @@ Migrating to the stable version of `react-router` is optional for the time being. But if you want to do the same for your existing repository, please - follow [this - guide](https://backstage.io/docs/tutorials/react-router-stable-migration). + follow [this guide](https://backstage.io/docs/tutorials/react-router-stable-migration). - e05e0f021b: Update versions of packages used in the create-app template, to match those in the main repo - 52f25858a8: Added `*.session.sql` Visual Studio Code database functionality files to `.gitignore` in the default template. This is optional but potentially helpful if your developers use Visual Studio Code; you can add a line with that exact value to your own root `.gitignore` if you want the same. @@ -3154,8 +3188,7 @@ The old `sqlite3` NPM library has been abandoned by its maintainers, which has led to unhandled security reports and other issues. Therefore, in the `knex` 1.x - release line they have instead switched over to the [`@vscode/sqlite3` - library](https://github.com/microsoft/vscode-node-sqlite3) by default, which is + release line they have instead switched over to the [`@vscode/sqlite3` library](https://github.com/microsoft/vscode-node-sqlite3) by default, which is actively maintained by Microsoft. This means that as you update to this version of Backstage, there are two @@ -3224,8 +3257,7 @@ The old `sqlite3` NPM library has been abandoned by its maintainers, which has led to unhandled security reports and other issues. Therefore, in the `knex` 1.x - release line they have instead switched over to the [`@vscode/sqlite3` - library](https://github.com/microsoft/vscode-node-sqlite3) by default, which is + release line they have instead switched over to the [`@vscode/sqlite3` library](https://github.com/microsoft/vscode-node-sqlite3) by default, which is actively maintained by Microsoft. This means that as you update to this version of Backstage, there are two diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 28e2fd1087..5f6566e78a 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.5.15-next.0", + "version": "0.5.16-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/seed-yarn.lock b/packages/create-app/seed-yarn.lock index 00a86105cc..7fd814bf99 100644 --- a/packages/create-app/seed-yarn.lock +++ b/packages/create-app/seed-yarn.lock @@ -16,3 +16,8 @@ // package: the name of the package, e.g. @testing-library/react // query: the version query to pin the version for, e.g. ^14.0.0 // version: the version to pin to, must be in range of the query, e.g. 14.11.0 + +"@swc/core@^1.3.46": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.5.7.tgz#e1db7b9887d5f34eb4a3256a738d0c5f1b018c33" + integrity sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ== diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index f2f35360cc..d0c2467ca9 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -39,7 +39,7 @@ "lerna": "^7.3.0", "node-gyp": "^9.0.0", "prettier": "^2.3.2", - "typescript": "~5.3.0" + "typescript": "~5.4.0" }, "resolutions": { "@types/react": "^18", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 4b29d5fc31..e8389d7744 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/dev-utils +## 1.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog-react@1.12.1-next.0 + +## 1.0.32 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/app-defaults@1.5.5 + - @backstage/integration-react@1.1.27 + +## 1.0.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration-react@1.1.27-next.0 + +## 1.0.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/integration-react@1.1.26 + ## 1.0.32-next.0 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index e987314494..e8ad8164bb 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.0.32-next.0", + "version": "1.0.33-next.0", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 4aec992020..d593501998 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,28 @@ # e2e-test +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.16-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.4 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.15 + +## 0.2.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.15-next.1 + ## 0.2.16-next.0 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index ae4b15aec0..aab8e4e99f 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.2.16-next.0", + "version": "0.2.17-next.0", "private": true, "backstage": { "role": "cli" @@ -43,7 +43,6 @@ "@backstage/cli": "workspace:^", "@types/fs-extra": "^11.0.0", "@types/node": "^18.17.8", - "@types/puppeteer": "^7.0.0", "nodemon": "^3.0.1" }, "nodemonConfig": { diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 60dde12184..63a7650400 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/eslint-plugin +## 0.1.8 + +### Patch Changes + +- 65ec043: add some `pickers` fixes + ## 0.1.7 ### Patch Changes diff --git a/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md b/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md index a105014abc..e2143354d2 100644 --- a/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md +++ b/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md @@ -41,3 +41,50 @@ import { import Typography from '@material-ui/core/Typography'; import Box from '@material-ui/core/Box'; ``` + +## --fix known issues + +This rule provides automatic fixes for the imports, but it has some known issues: + +### Non Props types import + +The fix will handle correctly 3 groups of imports: + +- Any import from related to styles (i.e `makeStyles`, `styled`, `WithStyles`) will be auto fixed to the `@material-ui/core/styles` import. +- Any import with `Props` suffix will be auto fixed to actual component for example `DialogProps` will be imported from `@material-ui/core/Dialog`. +- Any other import will be considered as a component import and will be auto fixed to the actual component import. + +This means that some types of imports without `Props` suffix will be wrongly auto fixed to the component import, for example this fix will be wrong: + +```diff +- import { Alert, Color } from '@material-ui/lab'; ++ import Alert from '@material-ui/lab/Alert'; ++ import Color from '@material-ui/lab/Color'; // this import is wrong +``` + +The correct import should look like this: + +```diff +- import { Alert, Color } from '@material-ui/lab'; ++ import Alert, {Color} from '@material-ui/lab/Alert'; +``` + +Because `Color` is a type coming from the Alert component. + +### No default export available + +Some components do not have a default export, for example `@material-ui/pickers/DateTimePicker` does not have a default export, so the fix will not work for these cases. + +The fix will be wrong for this import: + +```diff +- import { DateTimePicker } from '@material-ui/pickers'; ++ import DateTimePicker from '@material-ui/pickers/DateTimePicker'; // this default import does not exist +``` + +The correct import should look like this: + +```diff +- import { DateTimePicker } from '@material-ui/pickers'; ++ import { DateTimePicker } from '@material-ui/pickers/DateTimePicker'; // this is the correct import +``` diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 395a3eea64..0d8db000e0 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/eslint-plugin", - "version": "0.1.7", + "version": "0.1.8", "description": "Backstage ESLint plugin", "publishConfig": { "access": "public" diff --git a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js index 77adcad215..78fd3d63e9 100644 --- a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js +++ b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js @@ -27,7 +27,23 @@ */ const KNOWN_STYLES = [ - // TODO: add exports from colorManipulator and transitions + // colorManipulator + 'hexToRgb', + 'rgbToHex', + 'hslToRgb', + 'decomposeColor', + 'recomposeColor', + 'getContrastRatio', + 'getLuminance', + 'emphasize', + 'fade', + 'alpha', + 'darken', + 'lighten', + // transitions + 'easing', + 'duration', + // styles 'createTheme', 'unstable_createMuiStrictModeTheme', 'createMuiTheme', @@ -139,7 +155,11 @@ module.exports = { const value = s.imported.name; const alias = s.local.name === value ? undefined : s.local.name; - const propsMatch = /^([A-Z]\w+)Props$/.exec(value); + const propsMatch = + /^([A-Z]\w+)Props$/.exec(value) ?? + (node.source.value === '@material-ui/pickers' + ? /^Keyboard([A-Z]\w+Picker)$/.exec(value) + : null); const emitProp = propsMatch !== null; const emitComponent = !emitProp; @@ -188,7 +208,7 @@ module.exports = { if (specifier.emitProp && !specifier.emitComponent) { const replacement = `import { ${getNamedImportValue( specifier, - )} } from '@material-ui/core/${specifier.componentValue}';`; + )} } from '${node.source.value}/${specifier.componentValue}';`; replacements.push(replacement); } @@ -197,9 +217,9 @@ module.exports = { replacements.push( `import ${ specifier.componentAlias ?? specifier.componentValue - }, { ${getNamedImportValue( - specifier, - )} } from '@material-ui/core/${specifier.componentValue}';`, + }, { ${getNamedImportValue(specifier)} } from '${ + node.source.value + }/${specifier.componentValue}';`, ); } } diff --git a/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts index 2d29c2f9e9..4b675bd038 100644 --- a/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts +++ b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts @@ -93,6 +93,8 @@ import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, ThemeProvider, WithStyles, Tooltip as MaterialTooltip, + alpha, + easing } from '@material-ui/core';`, errors: [{ messageId: 'topLevelImport' }], output: `import Box from '@material-ui/core/Box'; @@ -101,7 +103,7 @@ import DialogContent from '@material-ui/core/DialogContent'; import DialogTitle from '@material-ui/core/DialogTitle'; import Grid from '@material-ui/core/Grid'; import MaterialTooltip from '@material-ui/core/Tooltip'; -import { makeStyles, ThemeProvider, WithStyles } from '@material-ui/core/styles';`, +import { makeStyles, ThemeProvider, WithStyles, alpha, easing } from '@material-ui/core/styles';`, }, { code: `import { Box, Button, makeStyles } from '@material-ui/core';`, @@ -111,11 +113,11 @@ import Button from '@material-ui/core/Button'; import { makeStyles } from '@material-ui/core/styles';`, }, { - code: `import { Paper, Typography, styled, withStyles } from '@material-ui/core';`, + code: `import { Paper, Typography, styled, withStyles, alpha, duration} from '@material-ui/core';`, errors: [{ messageId: 'topLevelImport' }], output: `import Paper from '@material-ui/core/Paper'; import Typography from '@material-ui/core/Typography'; -import { styled, withStyles } from '@material-ui/core/styles';`, +import { styled, withStyles, alpha, duration } from '@material-ui/core/styles';`, }, { code: `import { styled } from '@material-ui/core';`, @@ -152,5 +154,17 @@ import { styled, withStyles } from '@material-ui/core/styles';`, errors: [{ messageId: 'topLevelImport' }], output: `import { styled as s } from '@material-ui/core/styles';`, }, + { + code: `import { TreeItem, TreeItemProps, TreeView, AlertProps } from '@material-ui/lab';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import TreeItem, { TreeItemProps } from '@material-ui/lab/TreeItem'; +import TreeView from '@material-ui/lab/TreeView'; +import { AlertProps } from '@material-ui/lab/Alert';`, + }, + { + code: `import { KeyboardDatePicker } from '@material-ui/pickers';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import { KeyboardDatePicker } from '@material-ui/pickers/DatePicker';`, + }, ], }); diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index f7d85d19cf..53661a3b7c 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/frontend-app-api +## 0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## 0.7.0 + +### Minor Changes + +- ddddecb: Extensions in app-config now always affect ordering. Previously, only when enabling disabled extensions did they rise to the top. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/frontend-plugin-api@0.6.5 + +## 0.7.0-next.2 + +### Minor Changes + +- ddddecb: Extensions in app-config now always affect ordering. Previously, only when enabling disabled extensions did they rise to the top. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7-next.2 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## 0.6.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + ## 0.6.5-next.0 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index c131e81b41..8789f9fbeb 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.6.5-next.0", + "version": "0.7.1-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-app-api/src/setupTests.ts b/packages/frontend-app-api/src/setupTests.ts index c30f1d15cb..9abf7083b5 100644 --- a/packages/frontend-app-api/src/setupTests.ts +++ b/packages/frontend-app-api/src/setupTests.ts @@ -15,3 +15,18 @@ */ import '@testing-library/jest-dom'; + +// eslint-disable-next-line no-console +const originalConsoleWarn = console.warn; +// eslint-disable-next-line no-console +console.warn = (...args: any[]) => { + const message = args[0]; + if ( + typeof message === 'string' && + (message.includes('CSSOM.parse is not a function') || + message.includes('[JSS]')) + ) { + return; + } + originalConsoleWarn(...args); +}; diff --git a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts index 82f274b960..8af2aef070 100644 --- a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts +++ b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts @@ -110,6 +110,12 @@ describe('resolveAppNodeSpecs', () => { ], }), ).toEqual([ + { + id: 'b', + extension: b, + attachTo: { id: 'derp', input: 'default' }, + disabled: false, + }, { id: 'test/a', extension: makeExt('test/a'), @@ -117,12 +123,6 @@ describe('resolveAppNodeSpecs', () => { source: pluginA, disabled: false, }, - { - id: 'b', - extension: b, - attachTo: { id: 'derp', input: 'default' }, - disabled: false, - }, ]); }); @@ -206,6 +206,70 @@ describe('resolveAppNodeSpecs', () => { ]); }); + it('should place config-mentioned instances in the order that they were listed, irrespective of if the extension was enabled or not originally', () => { + const a = makeExt('a', 'disabled'); + const b = makeExt('b', 'enabled'); + const c = makeExt('c', 'disabled'); + const d = makeExt('d', 'enabled'); + const e = makeExt('e', 'disabled'); + const f = makeExt('f', 'enabled'); + const g = makeExt('g', 'disabled'); + expect( + resolveAppNodeSpecs({ + features: [createPlugin({ id: 'empty', extensions: [] })], + builtinExtensions: [a, b, c, d, e, f, g], + parameters: [ + { id: 'e', disabled: false }, + { id: 'd', disabled: false }, + { id: 'c', disabled: false }, + ], + }), + ).toEqual([ + { + id: 'e', + extension: e, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + { + id: 'd', + extension: d, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + { + id: 'c', + extension: c, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + { + id: 'a', + extension: a, + attachTo: { id: 'root', input: 'default' }, + disabled: true, + }, + { + id: 'b', + extension: b, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + { + id: 'f', + extension: f, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + { + id: 'g', + extension: g, + attachTo: { id: 'root', input: 'default' }, + disabled: true, + }, + ]); + }); + it('should apply extension overrides', () => { const plugin = createPlugin({ id: 'test', diff --git a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts index f056e7a49e..e31c70025d 100644 --- a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts +++ b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts @@ -184,6 +184,7 @@ export function resolveAppNodeSpecs(options: { ); } + const order = new Map(); for (const overrideParam of parameters) { const extensionId = overrideParam.id; @@ -193,11 +194,10 @@ export function resolveAppNodeSpecs(options: { ); } - const existingIndex = configuredExtensions.findIndex( + const existing = configuredExtensions.find( e => e.extension.id === extensionId, ); - if (existingIndex !== -1) { - const existing = configuredExtensions[existingIndex]; + if (existing) { if (overrideParam.attachTo) { existing.params.attachTo = overrideParam.attachTo; } @@ -209,18 +209,19 @@ export function resolveAppNodeSpecs(options: { Boolean(existing.params.disabled) !== Boolean(overrideParam.disabled) ) { existing.params.disabled = Boolean(overrideParam.disabled); - if (!existing.params.disabled) { - // bump - configuredExtensions.splice(existingIndex, 1); - configuredExtensions.push(existing); - } } + order.set(extensionId, existing); } else { throw new Error(`Extension ${extensionId} does not exist`); } } - return configuredExtensions.map(param => ({ + const orderedExtensions = [ + ...order.values(), + ...configuredExtensions.filter(e => !order.has(e.extension.id)), + ]; + + return orderedExtensions.map(param => ({ id: param.extension.id, attachTo: param.params.attachTo, extension: param.extension, diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 222732d4db..0d054e2549 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/frontend-plugin-api +## 0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## 0.6.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.7 + +## 0.6.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + ## 0.6.5-next.0 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 802ab13d41..1a21344f8d 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.6.5-next.0", + "version": "0.6.6-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/src/setupTests.ts b/packages/frontend-plugin-api/src/setupTests.ts index c30f1d15cb..9abf7083b5 100644 --- a/packages/frontend-plugin-api/src/setupTests.ts +++ b/packages/frontend-plugin-api/src/setupTests.ts @@ -15,3 +15,18 @@ */ import '@testing-library/jest-dom'; + +// eslint-disable-next-line no-console +const originalConsoleWarn = console.warn; +// eslint-disable-next-line no-console +console.warn = (...args: any[]) => { + const message = args[0]; + if ( + typeof message === 'string' && + (message.includes('CSSOM.parse is not a function') || + message.includes('[JSS]')) + ) { + return; + } + originalConsoleWarn(...args); +}; diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts index c180dc9719..dab8a9778a 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts @@ -187,7 +187,7 @@ describe('createPlugin', () => { await expect( screen.findByText( - 'Names: extension-1, extension-2-renamed, extension-3:child', + 'Names: extension-2-renamed, extension-1, extension-3:child', ), ).resolves.toBeInTheDocument(); }); diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index b0f052b3ee..b8dfd8335d 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/frontend-test-utils +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.1-next.0 + - @backstage/test-utils@1.5.6-next.0 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/types@1.1.1 + +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.0 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/test-utils@1.5.5 + +## 0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.0-next.2 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.6.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + ## 0.1.7-next.0 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 862d4c449f..8f849be064 100644 --- a/packages/frontend-test-utils/package.json +++ b/packages/frontend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-test-utils", - "version": "0.1.7-next.0", + "version": "0.1.8-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-test-utils/src/setupTests.ts b/packages/frontend-test-utils/src/setupTests.ts index c30f1d15cb..9abf7083b5 100644 --- a/packages/frontend-test-utils/src/setupTests.ts +++ b/packages/frontend-test-utils/src/setupTests.ts @@ -15,3 +15,18 @@ */ import '@testing-library/jest-dom'; + +// eslint-disable-next-line no-console +const originalConsoleWarn = console.warn; +// eslint-disable-next-line no-console +console.warn = (...args: any[]) => { + const message = args[0]; + if ( + typeof message === 'string' && + (message.includes('CSSOM.parse is not a function') || + message.includes('[JSS]')) + ) { + return; + } + originalConsoleWarn(...args); +}; diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index b12e621a60..f44e72919c 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/integration-react +## 1.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.11.0 + +## 1.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.11.0-next.0 + ## 1.1.26 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index c77bd26f27..07effadbae 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.1.26", + "version": "1.1.27", "description": "Frontend package for managing integrations towards external systems", "backstage": { "role": "web-library" diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 8a4616bfd7..0c00b80d58 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/integration +## 1.11.0 + +### Minor Changes + +- 2cc750d: Added `HarnessIntegration` via the `ScmIntegrations` interface. + +## 1.11.0-next.0 + +### Minor Changes + +- 2cc750d: Added `HarnessIntegration` via the `ScmIntegrations` interface. + ## 1.10.0 ### Minor Changes diff --git a/packages/integration/api-report.md b/packages/integration/api-report.md index 6b691dff80..2029dac600 100644 --- a/packages/integration/api-report.md +++ b/packages/integration/api-report.md @@ -513,6 +513,17 @@ export function getGitLabRequestOptions(config: GitLabIntegrationConfig): { headers: Record; }; +// @public +export function getHarnessFileContentsUrl( + config: HarnessIntegrationConfig, + url: string, +): string; + +// @public +export function getHarnessRequestOptions(config: HarnessIntegrationConfig): { + headers?: Record; +}; + // @public export class GiteaIntegration implements ScmIntegration { constructor(config: GiteaIntegrationConfig); @@ -674,6 +685,34 @@ export type GoogleGcsIntegrationConfig = { privateKey?: string; }; +// @public +export class HarnessIntegration implements ScmIntegration { + constructor(config: HarnessIntegrationConfig); + // (undocumented) + readonly config: HarnessIntegrationConfig; + // (undocumented) + static factory: ScmIntegrationsFactory; + // (undocumented) + resolveEditUrl(url: string): string; + // (undocumented) + resolveUrl(options: { + url: string; + base: string; + lineNumber?: number | undefined; + }): string; + // (undocumented) + get title(): string; + // (undocumented) + get type(): string; +} + +// @public +export type HarnessIntegrationConfig = { + host: string; + token?: string; + apiKey?: string; +}; + // @public export interface IntegrationsByType { // (undocumented) @@ -696,6 +735,8 @@ export interface IntegrationsByType { github: ScmIntegrationsGroup; // (undocumented) gitlab: ScmIntegrationsGroup; + // (undocumented) + harness: ScmIntegrationsGroup; } // @public @@ -839,6 +880,9 @@ export function readGoogleGcsIntegrationConfig( config: Config, ): GoogleGcsIntegrationConfig; +// @public +export function readHarnessConfig(config: Config): HarnessIntegrationConfig; + // @public @deprecated (undocumented) export const replaceGitHubUrlType: typeof replaceGithubUrlType; @@ -889,6 +933,8 @@ export interface ScmIntegrationRegistry github: ScmIntegrationsGroup; // (undocumented) gitlab: ScmIntegrationsGroup; + // (undocumented) + harness: ScmIntegrationsGroup; resolveEditUrl(url: string): string; resolveUrl(options: { url: string; @@ -927,6 +973,8 @@ export class ScmIntegrations implements ScmIntegrationRegistry { // (undocumented) get gitlab(): ScmIntegrationsGroup; // (undocumented) + get harness(): ScmIntegrationsGroup; + // (undocumented) list(): ScmIntegration[]; // (undocumented) resolveEditUrl(url: string): string; diff --git a/packages/integration/config.d.ts b/packages/integration/config.d.ts index 44303bf25c..58dd9153c4 100644 --- a/packages/integration/config.d.ts +++ b/packages/integration/config.d.ts @@ -345,5 +345,23 @@ export interface Config { */ password?: string; }>; + /** Integration configuration for Harness Code */ + harness?: Array<{ + /** + * The hostname of the given Harness Code instance + * @visibility frontend + */ + host: string; + /** + * The apikey to use for authenticated requests. + * @visibility secret + */ + apiKey?: string; + /** + * Harness Code token used to authenticate requests. This can be either a generated access token. + * @visibility secret + */ + token?: string; + }>; }; } diff --git a/packages/integration/package.json b/packages/integration/package.json index bbd0eecbe7..da4b700fd6 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "1.10.0", + "version": "1.11.0", "description": "Helpers for managing integrations towards external systems", "backstage": { "role": "common-library" diff --git a/packages/integration/src/ScmIntegrations.test.ts b/packages/integration/src/ScmIntegrations.test.ts index acf602e38d..c758816c03 100644 --- a/packages/integration/src/ScmIntegrations.test.ts +++ b/packages/integration/src/ScmIntegrations.test.ts @@ -38,6 +38,7 @@ import { ScmIntegrations } from './ScmIntegrations'; import { GiteaIntegration, GiteaIntegrationConfig } from './gitea'; import { AwsCodeCommitIntegration } from './awsCodeCommit/AwsCodeCommitIntegration'; import { AwsCodeCommitIntegrationConfig } from './awsCodeCommit'; +import { HarnessIntegration, HarnessIntegrationConfig } from './harness'; describe('ScmIntegrations', () => { const awsS3 = new AwsS3Integration({ @@ -80,6 +81,10 @@ describe('ScmIntegrations', () => { host: 'gitea.local', } as GiteaIntegrationConfig); + const harness = new HarnessIntegration({ + host: 'harness.local', + } as HarnessIntegrationConfig); + const i = new ScmIntegrations({ awsS3: basicIntegrations([awsS3], item => item.config.host), awsCodeCommit: basicIntegrations([awsCodeCommit], item => item.config.host), @@ -94,6 +99,7 @@ describe('ScmIntegrations', () => { github: basicIntegrations([github], item => item.config.host), gitlab: basicIntegrations([gitlab], item => item.config.host), gitea: basicIntegrations([gitea], item => item.config.host), + harness: basicIntegrations([harness], item => item.config.host), }); it('can get the specifics', () => { @@ -113,6 +119,7 @@ describe('ScmIntegrations', () => { expect(i.github.byUrl('https://github.local')).toBe(github); expect(i.gitlab.byUrl('https://gitlab.local')).toBe(gitlab); expect(i.gitea.byUrl('https://gitea.local')).toBe(gitea); + expect(i.harness.byUrl('https://harness.local')).toBe(harness); }); it('can list', () => { @@ -128,6 +135,7 @@ describe('ScmIntegrations', () => { github, gitlab, gitea, + harness, ]), ); }); @@ -143,6 +151,7 @@ describe('ScmIntegrations', () => { expect(i.byUrl('https://github.local')).toBe(github); expect(i.byUrl('https://gitlab.local')).toBe(gitlab); expect(i.byUrl('https://gitea.local')).toBe(gitea); + expect(i.byUrl('https://harness.local')).toBe(harness); expect(i.byHost('awss3.local')).toBe(awsS3); expect(i.byHost('awscodecommit.local')).toBe(awsCodeCommit); diff --git a/packages/integration/src/ScmIntegrations.ts b/packages/integration/src/ScmIntegrations.ts index 6a1faaa75b..e0d430d834 100644 --- a/packages/integration/src/ScmIntegrations.ts +++ b/packages/integration/src/ScmIntegrations.ts @@ -28,6 +28,7 @@ import { defaultScmResolveUrl } from './helpers'; import { ScmIntegration, ScmIntegrationsGroup } from './types'; import { ScmIntegrationRegistry } from './registry'; import { GiteaIntegration } from './gitea'; +import { HarnessIntegration } from './harness/HarnessIntegration'; /** * The set of supported integrations. @@ -48,6 +49,7 @@ export interface IntegrationsByType { github: ScmIntegrationsGroup; gitlab: ScmIntegrationsGroup; gitea: ScmIntegrationsGroup; + harness: ScmIntegrationsGroup; } /** @@ -70,6 +72,7 @@ export class ScmIntegrations implements ScmIntegrationRegistry { github: GithubIntegration.factory({ config }), gitlab: GitLabIntegration.factory({ config }), gitea: GiteaIntegration.factory({ config }), + harness: HarnessIntegration.factory({ config }), }); } @@ -120,6 +123,10 @@ export class ScmIntegrations implements ScmIntegrationRegistry { return this.byType.gitea; } + get harness(): ScmIntegrationsGroup { + return this.byType.harness; + } + list(): ScmIntegration[] { return Object.values(this.byType).flatMap( i => i.list() as ScmIntegration[], diff --git a/packages/integration/src/harness/HarnessIntegration.test.ts b/packages/integration/src/harness/HarnessIntegration.test.ts new file mode 100644 index 0000000000..2d85204f16 --- /dev/null +++ b/packages/integration/src/harness/HarnessIntegration.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 { ConfigReader } from '@backstage/config'; +import { HarnessIntegration } from './HarnessIntegration'; + +describe('HarnessIntegration', () => { + it('has a working factory', () => { + const integrations = HarnessIntegration.factory({ + config: new ConfigReader({ + integrations: { + harness: [ + { + host: 'app.harness.io', + token: '1234', + }, + ], + }, + }), + }); + expect(integrations.list().length).toBe(1); + expect(integrations.list()[0].config.host).toBe('app.harness.io'); + }); + + it('returns the basics', () => { + const integration = new HarnessIntegration({ + host: 'app.harness.io', + }); + expect(integration.type).toBe('harness'); + expect(integration.title).toBe('app.harness.io'); + }); + + describe('resolveUrl', () => { + it('works for valid urls, ignoring line number', () => { + const integration = new HarnessIntegration({ + host: 'app.harness.io', + }); + + expect( + integration.resolveUrl({ + url: 'https://app.harness.io/catalog-info.yaml', + base: 'https://app.harness.io/catalog-info.yaml', + lineNumber: 9, + }), + ).toBe('https://app.harness.io/catalog-info.yaml'); + }); + + it('handles line numbers', () => { + const integration = new HarnessIntegration({ + host: 'app.harness.io', + }); + + expect( + integration.resolveUrl({ + url: '', + base: 'https://app.harness.io/catalog-info.yaml#4', + lineNumber: 9, + }), + ).toBe('https://app.harness.io/catalog-info.yaml#L9'); + }); + }); + + describe('resolves with a relative url', () => { + it('works for valid urls', () => { + const integration = new HarnessIntegration({ + host: 'app.harness.io', + }); + + expect( + integration.resolveUrl({ + url: './skeleton', + base: 'https://app.harness.io/git/plugins/repo/+/refs/heads/master/template.yaml', + }), + ).toBe( + 'https://app.harness.io/git/plugins/repo/+/refs/heads/master/skeleton', + ); + }); + }); + + describe('resolves with an absolute url', () => { + it('works for valid urls', () => { + const integration = new HarnessIntegration({ + host: 'app.harness.io', + }); + + expect( + integration.resolveUrl({ + url: '/catalog-info.yaml', + base: 'https://app.harness.io/git/repo/+/refs/heads/master/', + }), + ).toBe( + 'https://app.harness.io/git/repo/+/refs/heads/master/catalog-info.yaml', + ); + }); + }); + + it('resolve edit URL', () => { + const integration = new HarnessIntegration({ + host: 'app.harness.io', + }); + + expect( + integration.resolveEditUrl( + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/edit/refMain/~/all-apis.yaml', + ), + ).toBe( + 'https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/+/edit/all-apis.yaml', + ); + }); +}); diff --git a/packages/integration/src/harness/HarnessIntegration.ts b/packages/integration/src/harness/HarnessIntegration.ts new file mode 100644 index 0000000000..5d1b274149 --- /dev/null +++ b/packages/integration/src/harness/HarnessIntegration.ts @@ -0,0 +1,58 @@ +/* + * 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 { basicIntegrations, defaultScmResolveUrl } from '../helpers'; +import { ScmIntegration, ScmIntegrationsFactory } from '../types'; +import { HarnessIntegrationConfig, readHarnessConfig } from './config'; +import { getHarnessEditContentsUrl } from './core'; + +/** + * A Harness Code based integration. + * + * @public + */ +export class HarnessIntegration implements ScmIntegration { + static factory: ScmIntegrationsFactory = ({ config }) => { + const configs = config.getOptionalConfigArray('integrations.harness') ?? []; + const harnessConfigs = configs.map(c => readHarnessConfig(c)); + + return basicIntegrations( + harnessConfigs.map(c => new HarnessIntegration(c)), + (harness: HarnessIntegration) => harness.config.host, + ); + }; + + constructor(readonly config: HarnessIntegrationConfig) {} + + get type(): string { + return 'harness'; + } + + get title(): string { + return this.config.host; + } + + resolveUrl(options: { + url: string; + base: string; + lineNumber?: number | undefined; + }): string { + return defaultScmResolveUrl(options); + } + + resolveEditUrl(url: string): string { + return getHarnessEditContentsUrl(this.config, url); + } +} diff --git a/packages/integration/src/harness/config.test.ts b/packages/integration/src/harness/config.test.ts new file mode 100644 index 0000000000..93be1fcc32 --- /dev/null +++ b/packages/integration/src/harness/config.test.ts @@ -0,0 +1,98 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config, ConfigReader } from '@backstage/config'; +import { loadConfigSchema } from '@backstage/config-loader'; +import { HarnessIntegrationConfig, readHarnessConfig } from './config'; + +describe('readHarnessConfig', () => { + function buildConfig(data: Partial): Config { + return new ConfigReader(data); + } + + async function buildFrontendConfig( + data: Partial, + ): Promise { + const fullSchema = await loadConfigSchema({ + dependencies: ['@backstage/integration'], + }); + const serializedSchema = fullSchema.serialize() as { + schemas: { value: { properties?: { integrations?: object } } }[]; + }; + const schema = await loadConfigSchema({ + serialized: { + ...serializedSchema, // only include schemas that apply to integrations + schemas: serializedSchema.schemas.filter( + s => s.value?.properties?.integrations, + ), + }, + }); + const processed = schema.process( + [{ data: { integrations: { harness: [data] } }, context: 'app' }], + { visibility: ['frontend'] }, + ); + return new ConfigReader((processed[0].data as any).integrations.harness[0]); + } + + it('reads all values', () => { + const output = readHarnessConfig( + buildConfig({ + host: 'a.com', + token: 'p', + apiKey: 'a', + }), + ); + expect(output).toEqual({ + host: 'a.com', + token: 'p', + apiKey: 'a', + }); + }); + + it('can create a default value if the API base URL is missing', () => { + const output = readHarnessConfig( + buildConfig({ + host: 'a.com', + }), + ); + expect(output).toEqual({ + host: 'a.com', + token: undefined, + }); + }); + + it('rejects funky configs', () => { + const valid: any = { + host: 'a.com', + }; + expect(() => readHarnessConfig(buildConfig({ ...valid, host: 2 }))).toThrow( + /host/, + ); + }); + + it('works on the frontend', async () => { + expect( + readHarnessConfig( + await buildFrontendConfig({ + host: 'a.com', + token: 'p', + }), + ), + ).toEqual({ + host: 'a.com', + }); + }); +}); diff --git a/packages/integration/src/harness/config.ts b/packages/integration/src/harness/config.ts new file mode 100644 index 0000000000..2f75915567 --- /dev/null +++ b/packages/integration/src/harness/config.ts @@ -0,0 +1,61 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; +import { isValidHost } from '../helpers'; + +/** + * The configuration for a single Harness integration. + * + * @public + */ +export type HarnessIntegrationConfig = { + /** + * The host of the target that this matches on, e.g. "app.harness.io" + */ + host: string; + /** + * The password or http token to use for authentication. + */ + token?: string; + /** + * The API key to use for authentication. + */ + apiKey?: string; +}; + +/** + * Parses a location config block for use in HarnessIntegration + * + * @public + */ +export function readHarnessConfig(config: Config): HarnessIntegrationConfig { + const host = config.getString('host'); + const token = config.getOptionalString('token'); + const apiKey = config.getOptionalString('apiKey'); + + if (!isValidHost(host)) { + throw new Error( + `Invalid Harness Code integration config, '${host}' is not a valid host`, + ); + } + + return { + host, + apiKey, + token, + }; +} diff --git a/packages/integration/src/harness/core.test.ts b/packages/integration/src/harness/core.test.ts new file mode 100644 index 0000000000..d3d402806a --- /dev/null +++ b/packages/integration/src/harness/core.test.ts @@ -0,0 +1,91 @@ +/* + * 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 { setupServer } from 'msw/node'; +import { setupRequestMockHandlers } from '../helpers'; +import { HarnessIntegrationConfig } from './config'; +import { + getHarnessEditContentsUrl, + getHarnessFileContentsUrl, + getHarnessRequestOptions, +} from './core'; + +describe('Harness code core', () => { + const worker = setupServer(); + setupRequestMockHandlers(worker); + + describe('getHarnessFileContentsUrl', () => { + it('can create an url from arguments', () => { + const config: HarnessIntegrationConfig = { + host: 'app.harness.io', + }; + expect( + getHarnessFileContentsUrl( + config, + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/all-apis.yaml', + ), + ).toEqual( + 'https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/+/raw/all-apis.yaml?routingId=accountId&git_ref=refMain', + ); + }); + }); + + describe('getHarnessEditContentsUrl', () => { + it('can create an url from arguments', () => { + const config: HarnessIntegrationConfig = { + host: 'app.harness.io', + }; + expect( + getHarnessEditContentsUrl( + config, + 'https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/edit/refMain/~/all-apis.yaml', + ), + ).toEqual( + 'https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/+/edit/all-apis.yaml', + ); + }); + }); + + describe('getHarnessRequestOptions', () => { + it('adds token header when only a token is specified', () => { + const authRequest: HarnessIntegrationConfig = { + host: 'app.harness.io', + token: 'P', + }; + const anonymousRequest: HarnessIntegrationConfig = { + host: 'app.harness.io', + }; + expect( + (getHarnessRequestOptions(authRequest).headers as any).Authorization, + ).toEqual('Bearer P'); + expect(getHarnessRequestOptions(anonymousRequest).headers).toStrictEqual( + {}, + ); + }); + + it('adds basic auth when apikey and token are specified', () => { + const authRequest: HarnessIntegrationConfig = { + host: 'app.harness.io', + token: 'P', + apiKey: 'a', + }; + + expect( + (getHarnessRequestOptions(authRequest).headers as any)['x-api-key'], + ).toEqual('a'); + }); + }); +}); diff --git a/packages/integration/src/harness/core.ts b/packages/integration/src/harness/core.ts new file mode 100644 index 0000000000..3a61905e27 --- /dev/null +++ b/packages/integration/src/harness/core.ts @@ -0,0 +1,132 @@ +/* + * 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 { HarnessIntegrationConfig } from './config'; + +/** + * Given a URL pointing to a file, returns a URL + * for editing the contents of the data. + * + * @remarks + * + * Converts + * from: https://app.harness.io/a/b/src/branchname/path/to/c.yaml + * or: https://app.harness.io/a/b/_edit/branchname/path/to/c.yaml + * + * @param url - A URL pointing to a file + * @param config - The relevant provider config + * @public + */ +export function getHarnessEditContentsUrl( + config: HarnessIntegrationConfig, + url: string, +) { + try { + const baseUrl = `https://${config.host}`; + const [ + _blank, + _ng, + _account, + accountId, + _module, + _moduleName, + _org, + orgName, + _projects, + projectName, + _repos, + repoName, + _files, + _ref, + _branch, + ...path + ] = url.replace(baseUrl, '').split('/'); + const pathWithoutSlash = path.join('/').replace(/^\//, ''); + return `${baseUrl}/gateway/code/api/v1/repos/${accountId}/${orgName}/${projectName}/${repoName}/+/edit/${pathWithoutSlash}`; + } catch (e) { + throw new Error(`Incorrect URL: ${url}, ${e}`); + } +} + +/** + * Given a file path URL, + * it returns an API URL which returns the contents of the file. + * @remarks + * + * Converts + * from: https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/all-apis.yaml + * to: https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/+/content/all-apis.yaml?routingId=accountId&include_commit=false&ref=refMain + * + * @param url - A URL pointing to a file + * @param config - The relevant provider config + * @public + */ +export function getHarnessFileContentsUrl( + config: HarnessIntegrationConfig, + url: string, +) { + try { + const baseUrl = `https://${config.host}`; + const [ + _blank, + _ng, + _account, + accountId, + _module, + _moduleName, + _org, + orgName, + _projects, + projectName, + _repos, + repoName, + _files, + _ref, + _branch, + ...path + ] = url.replace(baseUrl, '').split('/'); + const urlParts = url.replace(baseUrl, '').split('/'); + const refAndPath = urlParts.slice(13); + const refIndex = refAndPath.findIndex(item => item === '~'); + const refString = refAndPath.slice(0, refIndex); + const pathWithoutSlash = path.join('/').replace(/^\//, ''); + return `${baseUrl}/gateway/code/api/v1/repos/${accountId}/${orgName}/${projectName}/${repoName}/+/raw/${pathWithoutSlash}?routingId=${accountId}&git_ref=${refString}`; + } catch (e) { + throw new Error(`Incorrect URL: ${url}, ${e}`); + } +} + +/** + * Return request headers for a Harness Code provider. + * + * @param config - A Harness Code provider config + * @public + */ +export function getHarnessRequestOptions(config: HarnessIntegrationConfig): { + headers?: Record; +} { + const headers: Record = {}; + const { token, apiKey } = config; + + if (apiKey) { + headers['x-api-key'] = apiKey; + } else if (token) { + headers.Authorization = `Bearer ${token}`; + } + + return { + headers, + }; +} diff --git a/packages/integration/src/harness/index.ts b/packages/integration/src/harness/index.ts new file mode 100644 index 0000000000..264df657f0 --- /dev/null +++ b/packages/integration/src/harness/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { HarnessIntegration } from './HarnessIntegration'; +export { getHarnessRequestOptions, getHarnessFileContentsUrl } from './core'; +export { readHarnessConfig } from './config'; +export type { HarnessIntegrationConfig } from './config'; diff --git a/packages/integration/src/index.ts b/packages/integration/src/index.ts index b20477ee6a..32c573abef 100644 --- a/packages/integration/src/index.ts +++ b/packages/integration/src/index.ts @@ -31,6 +31,7 @@ export * from './gitea'; export * from './github'; export * from './gitlab'; export * from './googleGcs'; +export * from './harness'; export { defaultScmResolveUrl } from './helpers'; export { ScmIntegrations } from './ScmIntegrations'; export type { IntegrationsByType } from './ScmIntegrations'; diff --git a/packages/integration/src/registry.ts b/packages/integration/src/registry.ts index 00706acc1c..7e4b34cc34 100644 --- a/packages/integration/src/registry.ts +++ b/packages/integration/src/registry.ts @@ -25,6 +25,7 @@ import { GerritIntegration } from './gerrit/GerritIntegration'; import { GithubIntegration } from './github/GithubIntegration'; import { GitLabIntegration } from './gitlab/GitLabIntegration'; import { GiteaIntegration } from './gitea/GiteaIntegration'; +import { HarnessIntegration } from './harness/HarnessIntegration'; /** * Holds all registered SCM integrations, of all types. @@ -46,6 +47,7 @@ export interface ScmIntegrationRegistry github: ScmIntegrationsGroup; gitlab: ScmIntegrationsGroup; gitea: ScmIntegrationsGroup; + harness: ScmIntegrationsGroup; /** * Resolves an absolute or relative URL in relation to a base URL. * diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 7b2646ad2b..0f44f1ca88 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/repo-tools +## 0.9.1-next.1 + +### Patch Changes + +- 8721a02: Add `--client-additional-properties` option to `openapi generate` command +- Updated dependencies + - @backstage/backend-plugin-api@0.6.19-next.1 + - @backstage/cli-node@0.2.6-next.0 + - @backstage/config-loader@1.8.0 + +## 0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-node@0.2.6-next.0 + - @backstage/backend-plugin-api@0.6.19-next.0 + - @backstage/config-loader@1.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.4 + +## 0.9.0 + +### Minor Changes + +- 683870a: Adds 2 new commands `repo schema openapi diff` and `package schema openapi diff`. `repo schema openapi diff` is intended to power a new breaking changes check on pull requests and the package level command allows plugin developers to quickly see new API breaking changes. They're intended to be used in complement with the existing `repo schema openapi verify` command to validate your OpenAPI spec against a variety of things. + +### Patch Changes + +- 9ae9bb2: Update the paths logic in the api reports command to support complex subpaths +- d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-plugin-api@0.6.18 + +## 0.9.0-next.2 + +### Minor Changes + +- 683870a: Adds 2 new commands `repo schema openapi diff` and `package schema openapi diff`. `repo schema openapi diff` is intended to power a new breaking changes check on pull requests and the package level command allows plugin developers to quickly see new API breaking changes. They're intended to be used in complement with the existing `repo schema openapi verify` command to validate your OpenAPI spec against a variety of things. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.2 + +## 0.8.1-next.1 + +### Patch Changes + +- 9ae9bb2: Update the paths logic in the api reports command to support complex subpaths +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/cli-node@0.2.5 + - @backstage/config-loader@1.8.0 + ## 0.8.1-next.0 ### Patch Changes diff --git a/packages/repo-tools/cli-report.md b/packages/repo-tools/cli-report.md index 9d37ce7aff..a06f426baf 100644 --- a/packages/repo-tools/cli-report.md +++ b/packages/repo-tools/cli-report.md @@ -172,9 +172,20 @@ Commands: lint [options] [paths...] test [options] [paths...] fuzz [options] + diff [options] help [command] ``` +### `backstage-repo-tools repo schema openapi diff` + +``` +Usage: backstage-repo-tools repo schema openapi diff [options] + +Options: + --since + -h, --help +``` + ### `backstage-repo-tools repo schema openapi fuzz` ``` diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 5d53a9cff6..fa6e99485a 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,38 +1,49 @@ { "name": "@backstage/repo-tools", "description": "CLI for Backstage repo tooling ", - "version": "0.8.1-next.0", + "version": "0.9.1-next.1", "publishConfig": { "access": "public" }, "backstage": { "role": "cli" }, + "keywords": [ + "backstage" + ], "homepage": "https://backstage.io", "repository": { "type": "git", "url": "https://github.com/backstage/backstage", "directory": "packages/repo-tools" }, - "keywords": [ - "backstage" - ], "license": "Apache-2.0", "main": "dist/index.cjs.js", - "scripts": { - "build": "backstage-cli package build", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", - "clean": "backstage-cli package clean", - "start": "nodemon --" - }, "bin": { "backstage-repo-tools": "bin/backstage-repo-tools" }, + "files": [ + "bin", + "dist/**/*.js", + "templates", + "openapitools.json" + ], + "scripts": { + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "start": "nodemon --", + "test": "backstage-cli package test" + }, + "nodemonConfig": { + "exec": "bin/backstage-repo-tools", + "ext": "ts", + "watch": "./src" + }, "dependencies": { "@apidevtools/swagger-parser": "^10.1.0", "@apisyouwonthate/style-guide": "^1.4.0", - "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/cli-common": "workspace:^", "@backstage/cli-node": "workspace:^", @@ -49,6 +60,7 @@ "@stoplight/spectral-rulesets": "^1.18.0", "@stoplight/spectral-runtime": "^1.1.2", "@stoplight/types": "^14.0.0", + "@useoptic/openapi-utilities": "^0.54.8", "chalk": "^4.0.0", "codeowners-utils": "^1.0.2", "command-exists": "^1.2.9", @@ -83,16 +95,5 @@ "prettier": { "optional": true } - }, - "files": [ - "bin", - "dist/**/*.js", - "templates", - "openapitools.json" - ], - "nodemonConfig": { - "watch": "./src", - "exec": "bin/backstage-repo-tools", - "ext": "ts" } } diff --git a/packages/repo-tools/src/commands/index.ts b/packages/repo-tools/src/commands/index.ts index d2fe507941..24ec2af411 100644 --- a/packages/repo-tools/src/commands/index.ts +++ b/packages/repo-tools/src/commands/index.ts @@ -54,6 +54,10 @@ function registerPackageCommand(program: Command) { .description( 'Command to generate a client and/or a server stub from an OpenAPI spec.', ) + .option('--client-additional-properties [properties]') + .description( + 'Additional properties that can be passed to @openapitools/openapi-generator-cli', + ) .action( lazy(() => import('./package/schema/openapi/generate').then(m => m.command), @@ -78,6 +82,15 @@ function registerPackageCommand(program: Command) { .action( lazy(() => import('./package/schema/openapi/fuzz').then(m => m.command)), ); + + openApiCommand + .command('diff') + .option('--ignore', 'Ignore linting failures and only log the results.') + .option('--json', 'Output the results as JSON') + .option('--since ', 'Diff the API against a specific ref') + .action( + lazy(() => import('./package/schema/openapi/diff').then(m => m.command)), + ); } function registerRepoCommand(program: Command) { @@ -96,7 +109,7 @@ function registerRepoCommand(program: Command) { openApiCommand .command('verify [paths...]') .description( - 'Verify that all OpenAPI schemas are valid and have a matching `schemas/openapi.generated.ts` file.', + 'Verify that all OpenAPI schemas are valid and set up correctly.', ) .action( lazy(() => @@ -133,6 +146,20 @@ function registerRepoCommand(program: Command) { .action( lazy(() => import('./repo/schema/openapi/fuzz').then(m => m.command)), ); + + openApiCommand + .command('diff') + .description( + 'Diff the repository against a specific ref, will run all package `diff` scripts.', + ) + .option( + '--since ', + 'Diff the API against a specific ref', + 'origin/master', + ) + .action( + lazy(() => import('./repo/schema/openapi/diff').then(m => m.command)), + ); } export function registerCommands(program: Command) { diff --git a/packages/repo-tools/src/commands/package/schema/openapi/diff.ts b/packages/repo-tools/src/commands/package/schema/openapi/diff.ts new file mode 100644 index 0000000000..3cb0baf313 --- /dev/null +++ b/packages/repo-tools/src/commands/package/schema/openapi/diff.ts @@ -0,0 +1,93 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import chalk from 'chalk'; +import { exec } from '../../../../lib/exec'; +import { getPathToCurrentOpenApiSpec } from '../../../../lib/openapi/helpers'; +import { paths as cliPaths } from '../../../../lib/paths'; +import { OptionValues } from 'commander'; +import { env } from 'process'; +import { readFile, rm } from 'fs/promises'; +import { resolve } from 'path'; + +const reduceOpticOutput = (output: string) => { + return output + .split('\n') + .filter(e => !e.startsWith('Rerun') && e.trim()) + .join('\n'); +}; + +async function check(opts: OptionValues) { + const resolvedOpenapiPath = await getPathToCurrentOpenApiSpec(); + + let baseRef = opts.since; + if (!baseRef) { + const { stdout: branch } = await exec( + 'git merge-base --fork-point origin/master', + ); + baseRef = branch.toString().trim(); + } + + let failed = false; + let output = ''; + try { + const { stdout } = await exec( + 'yarn optic diff', + [ + resolvedOpenapiPath, + '--check', + opts.json ? '--json' : '', + '--base', + baseRef, + ], + { + cwd: cliPaths.targetRoot, + env: { CI: opts.json ? '1' : undefined, ...env }, + }, + ); + output = stdout.toString(); + } catch (err) { + output = err.stdout; + failed = true; + } + + if (opts.json) { + const file = ( + await readFile(resolve(cliPaths.targetRoot, 'ci-run-details.json')) + ).toString(); + const results = JSON.parse(file); + console.log(file); + if (!opts.ignore && results.failed) { + throw new Error('Some checks failed'); + } + + await rm(resolve(cliPaths.targetRoot, 'ci-run-details.json')); + } else { + console.log(reduceOpticOutput(output)); + if (!opts.ignore && failed) { + throw new Error('Some checks failed'); + } + } +} + +export async function command(opts: OptionValues) { + try { + await check(opts); + if (!opts.json) console.log(chalk.green(`All checks passed.`)); + } catch (err) { + if (!opts.json) console.log(chalk.red(err.message)); + process.exit(1); + } +} diff --git a/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts b/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts index 5dfed05f93..b843cd27ec 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts @@ -24,15 +24,21 @@ import { paths as cliPaths } from '../../../../../lib/paths'; import { mkdirpSync } from 'fs-extra'; import fs from 'fs-extra'; import { exec } from '../../../../../lib/exec'; -import { resolvePackagePath } from '@backstage/backend-common'; +import { resolvePackagePath } from '@backstage/backend-plugin-api'; import { getPathToCurrentOpenApiSpec } from '../../../../../lib/openapi/helpers'; -async function generate(outputDirectory: string) { +async function generate( + outputDirectory: string, + clientAdditionalProperties?: string, +) { const resolvedOpenapiPath = await getPathToCurrentOpenApiSpec(); const resolvedOutputDirectory = cliPaths.resolveTargetRoot( outputDirectory, OUTPUT_PATH, ); + const additionalProperties = clientAdditionalProperties + ? `--additional-properties=${clientAdditionalProperties}` + : ''; mkdirpSync(resolvedOutputDirectory); await fs.mkdirp(resolvedOutputDirectory); @@ -60,6 +66,7 @@ async function generate(outputDirectory: string) { ), '--generator-key', 'v3.0', + additionalProperties, ], { maxBuffer: Number.MAX_VALUE, @@ -87,9 +94,12 @@ async function generate(outputDirectory: string) { }); } -export async function command(outputPackage: string): Promise { +export async function command( + outputPackage: string, + clientAdditionalProperties?: string, +): Promise { try { - await generate(outputPackage); + await generate(outputPackage, clientAdditionalProperties); console.log( chalk.green(`Generated client in ${outputPackage}/${OUTPUT_PATH}`), ); diff --git a/packages/repo-tools/src/commands/package/schema/openapi/generate/index.ts b/packages/repo-tools/src/commands/package/schema/openapi/generate/index.ts index 1e48fe3825..41884e2e90 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/generate/index.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/generate/index.ts @@ -26,7 +26,7 @@ export async function command(opts: OptionValues) { process.exit(1); } if (opts.clientPackage) { - await generateClient(opts.clientPackage); + await generateClient(opts.clientPackage, opts.clientAdditionalProperties); } if (opts.server) { await generateServer(); diff --git a/packages/repo-tools/src/commands/repo/schema/openapi/diff.ts b/packages/repo-tools/src/commands/repo/schema/openapi/diff.ts new file mode 100644 index 0000000000..02f3db0c43 --- /dev/null +++ b/packages/repo-tools/src/commands/repo/schema/openapi/diff.ts @@ -0,0 +1,111 @@ +/* + * 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 { PackageGraph } from '@backstage/cli-node'; +import { OptionValues } from 'commander'; +import { exec } from '../../../../lib/exec'; +import { + CiRunDetails, + generateCompareSummaryMarkdown, +} from '../../../../lib/openapi/optic/helpers'; +import { paths as cliPaths } from '../../../../lib/paths'; +import { YAML_SCHEMA_PATH } from '../../../../lib/openapi/constants'; + +function cleanUpApiName(e: { apiName: string }) { + e.apiName = e.apiName + .replace(cliPaths.targetDir, '') + .replace(YAML_SCHEMA_PATH, ''); +} + +export async function command(opts: OptionValues) { + let packages = await PackageGraph.listTargetPackages(); + + let since = ''; + if (opts.since) { + const { stdout: sinceRaw } = await exec('git', ['rev-parse', opts.since]); + since = sinceRaw.toString().trim(); + const { stdout: changedFilesRaw } = await exec('git', [ + 'diff', + '--name-only', + since, + ]); + const changedFiles = changedFilesRaw.toString().trim(); + + const changedOpenApiSpecs = changedFiles + .split('\n') + .filter(e => e.endsWith(YAML_SCHEMA_PATH)) + .map(e => cliPaths.resolveTarget(e)); + + // filter packages by changedFiles + packages = packages.filter(pkg => + changedOpenApiSpecs.some(e => e.startsWith(`${pkg.dir}/`)), + ); + } + + const checkablePackages = packages.filter(e => e.packageJson.scripts?.diff); + + try { + const outputs = { + completed: [], + failed: [], + noop: [], + warning: [], + severity: 0, + } as CiRunDetails; + for (const pkg of checkablePackages) { + const sinceCommands = since ? ['--since', since] : []; + const { stdout } = await exec( + 'yarn', + ['diff', '--ignore', '--json', ...sinceCommands], + { + cwd: pkg.dir, + }, + ); + const result = JSON.parse(stdout.toString()); + outputs.completed.push(...(result.completed ?? [])); + outputs.failed.push(...(result.failed ?? [])); + outputs.noop.push(...(result.noop ?? [])); + } + + for (const pkg of packages.filter(e => !e.packageJson.scripts?.diff)) { + outputs.warning?.push({ + apiName: `${pkg.dir}/`, + warning: 'No diff script found in package.json', + }); + } + + outputs.completed.forEach(cleanUpApiName); + outputs.failed.forEach(cleanUpApiName); + outputs.noop.forEach(cleanUpApiName); + outputs.warning?.forEach(cleanUpApiName); + + const { stdout: currentSha } = await exec('git', ['rev-parse', 'HEAD']); + console.log( + generateCompareSummaryMarkdown( + { sha: currentSha.toString().trim() }, + outputs, + { verbose: true }, + ), + ); + + const failed = outputs.failed.length > 0; + if (failed) { + throw new Error('Some checks failed'); + } + } catch (err) { + console.error(err); + process.exit(1); + } +} diff --git a/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts b/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts index 442494610c..23e07d1230 100644 --- a/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts +++ b/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts @@ -38,7 +38,6 @@ async function verify(directoryPath: string) { // Unable to find spec at path. return; } - const yaml = YAML.load(await fs.readFile(openapiPath, 'utf8')); await Parser.validate(cloneDeep(yaml) as any); diff --git a/packages/repo-tools/src/lib/openapi/optic/helpers.ts b/packages/repo-tools/src/lib/openapi/optic/helpers.ts new file mode 100644 index 0000000000..9f5deb72e0 --- /dev/null +++ b/packages/repo-tools/src/lib/openapi/optic/helpers.ts @@ -0,0 +1,302 @@ +/* + * 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. + */ +/* eslint-disable no-nested-ternary */ + +import { + compareSpecs, + groupDiffsByEndpoint, + Severity, + getOperationsChangedLabel, + getOperationsChanged, +} from '@useoptic/openapi-utilities'; +import { GroupedDiffs } from '@useoptic/openapi-utilities/build/openapi3/group-diff'; + +/** + * The below code is copied from https://github.com/opticdev/optic/blob/main/projects/optic/src/commands/ci/comment/common.ts#L82 for use + * with a security flow for forked repositories. + */ + +type Comparison = { + groupedDiffs: ReturnType; + results: Awaited>['results']; +}; + +export type CiRunDetails = { + completed: { + warnings: string[]; + apiName: string; + opticWebUrl?: string | null; + comparison: Comparison; + specUrl?: string | null; + capture?: any; + }[]; + warning?: { apiName: string; warning: string }[]; + failed: { apiName: string; error: string }[]; + noop: { apiName: string }[]; + severity: Severity; +}; + +const getChecksLabel = ( + results: CiRunDetails['completed'][number]['comparison']['results'], + severity: Severity, +) => { + const totalChecks = results.length; + let failingChecks = 0; + let exemptedFailingChecks = 0; + + for (const result of results) { + if (result.passed) continue; + if (result.severity < severity) continue; + if (result.exempted) exemptedFailingChecks += 1; + else failingChecks += 1; + } + + const exemptedChunk = + exemptedFailingChecks > 0 ? `, ${exemptedFailingChecks} exempted` : ''; + + return failingChecks > 0 + ? `⚠️ **${failingChecks}**/**${totalChecks}** failed${exemptedChunk}` + : totalChecks > 0 + ? `✅ **${totalChecks}** passed${exemptedChunk}` + : `ℹ️ No automated checks have run`; +}; + +function getOperationsText( + groupedDiffs: GroupedDiffs, + options: { webUrl?: string | null; verbose: boolean; labelJoiner?: string }, +) { + const ops = getOperationsChanged(groupedDiffs); + + const operationsText = options.verbose + ? [ + ...[...ops.added].map(o => `\`${o}\` (added)`), + ...[...ops.changed].map(o => `\`${o}\` (changed)`), + ...[...ops.removed].map(o => `\`${o}\` (removed)`), + ].join('\n') + : ''; + return `${getOperationsChangedLabel(groupedDiffs)} + + ${operationsText} + `; +} + +const getCaptureIssuesLabel = ({ + unmatchedInteractions, + mismatchedEndpoints, +}: { + unmatchedInteractions: number; + mismatchedEndpoints: number; +}) => { + return [ + ...(unmatchedInteractions + ? [ + `🆕 ${unmatchedInteractions} undocumented path${ + unmatchedInteractions > 1 ? 's' : '' + }`, + ] + : []), + ...(mismatchedEndpoints + ? [ + `⚠️ ${mismatchedEndpoints} mismatch${ + mismatchedEndpoints > 1 ? 'es' : '' + }`, + ] + : []), + ].join('\n'); +}; + +const getBreakagesRow = (breakage: CiRunDetails['completed'][number]) => { + return ` + - ${breakage.apiName} + ${breakage.comparison.results.map( + s => ` + - ${s.where} + ${'```'} + ${s.error} + ${'```'}`, + )}`; +}; + +const addSummaryLine = (items: any[] | number | undefined, label: string) => { + const length = Array.isArray(items) ? items.length : items; + if (!length) return ''; + let text = length === 1 ? `1 API` : `${length} APIs`; + text += ` had ${label}`; + return text; +}; + +export const generateCompareSummaryMarkdown = ( + commit: { sha: string }, + results: CiRunDetails, + options: { verbose: boolean }, +) => { + const anyCompletedHasWarning = results.completed.some( + s => s.warnings.length > 0, + ); + const anyCompletedHasCapture = results.completed.some(s => s.capture); + if ( + results.completed.length === 0 && + results.failed.length === 0 && + results.failed.length === 0 + ) { + return `No API changes detected for commit (${commit.sha})`; + } + const breakages = results.completed + .filter(s => s.comparison.results.some(e => !e.passed)) + .map(e => ({ + ...e, + comparison: { + ...e.comparison, + results: e.comparison.results.filter(f => !f.passed), + }, + })); + const successfullyCompletedCount = + results.completed.length - breakages.length; + return `### Summary for commit (${commit.sha}) + +${addSummaryLine(results.noop, 'no changes')} + +${addSummaryLine(breakages.length, 'breaking changes')} + +${addSummaryLine(successfullyCompletedCount, 'non-breaking changes')} + +${addSummaryLine(results.warning, 'warnings')} + +${ + results.completed.length > 0 + ? `### APIs with Changes + +
+ + + + + +${anyCompletedHasWarning ? '' : ''} +${anyCompletedHasCapture ? '' : ''} + + + +${results.completed + .map( + s => + ` + + + + +${anyCompletedHasWarning ? `` : ''} + +${ + anyCompletedHasCapture + ? ` + +` + : '' +} +`, + ) + .join('\n')} + +
APIChangesRulesWarningsTests
+${s.apiName} + +${getOperationsText(s.comparison.groupedDiffs, { + webUrl: s.opticWebUrl, + verbose: options.verbose, + labelJoiner: ',\n', +})} + +${getChecksLabel(s.comparison.results, results.severity)} +${s.warnings.join('\n')} +${ + s.capture + ? s.capture.success + ? s.capture.mismatchedEndpoints || s.capture.unmatchedInteractions + ? getCaptureIssuesLabel({ + unmatchedInteractions: s.capture.unmatchedInteractions, + mismatchedEndpoints: s.capture.mismatchedEndpoints, + }) + : `✅ ${s.capture.percentCovered}% coverage` + : '❌ Failed to run' + : '' +} +
` + : '' +} + +${ + results.failed.length > 0 + ? `### APIs with Errors + + + + + + + + + +${results.failed + .map( + s => ` + + +`, + ) + .join('\n')} + +
APIError
${s.apiName} + +${'```'} +${s.error} +${'```'} + +
+` + : '' +} + +${ + results.warning && results.warning.length + ? ` +### APIs with Warnings + + + + + + + + + ${results.warning + .map(e => ``) + .join('\n')} + +
APIWarning
${e.apiName}${e.warning}
` + : '' +} +${ + breakages.length > 0 + ? ` +### Routes with Breakages + +${breakages.map(getBreakagesRow).join('\n')} +` + : '' +} +`; +}; diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 5764b6e71e..9fbc781d64 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,65 @@ # techdocs-cli-embedded-app +## 0.2.97-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.6-next.0 + - @backstage/theme@0.5.6-next.0 + - @backstage/cli@0.26.6-next.0 + - @backstage/app-defaults@1.5.6-next.0 + - @backstage/core-components@0.14.8-next.0 + - @backstage/test-utils@1.5.6-next.0 + - @backstage/plugin-techdocs-react@1.2.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/integration-react@1.1.27 + - @backstage/plugin-catalog@1.20.1-next.0 + +## 0.2.96 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.20.0 + - @backstage/cli@0.26.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-techdocs@1.10.5 + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + - @backstage/app-defaults@1.5.5 + - @backstage/integration-react@1.1.27 + - @backstage/test-utils@1.5.5 + - @backstage/plugin-techdocs-react@1.2.4 + +## 0.2.96-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.26.5-next.1 + - @backstage/plugin-techdocs@1.10.5-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/integration-react@1.1.27-next.0 + +## 0.2.96-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/app-defaults@1.5.5-next.1 + - @backstage/cli@0.26.5-next.0 + - @backstage/integration-react@1.1.26 + - @backstage/plugin-techdocs@1.10.5-next.1 + - @backstage/plugin-techdocs-react@1.2.4-next.1 + ## 0.2.96-next.0 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 00083edb6d..822b784bf3 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,6 +1,6 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.96-next.0", + "version": "0.2.97-next.0", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli-embedded-app/src/apis.ts b/packages/techdocs-cli-embedded-app/src/apis.ts index d48bee569d..5bb19a563d 100644 --- a/packages/techdocs-cli-embedded-app/src/apis.ts +++ b/packages/techdocs-cli-embedded-app/src/apis.ts @@ -72,7 +72,7 @@ class TechDocsDevStorageApi implements TechDocsStorageApi { } async getBuilder() { - return this.configApi.getString('techdocs.builder'); + return this.configApi.getOptionalString('techdocs.builder') || 'local'; } async getEntityDocs(_entityId: CompoundEntityRef, path: string) { diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 1525b13414..6f72a73b79 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,42 @@ # @techdocs/cli +## 1.8.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.0-next.1 + - @backstage/plugin-techdocs-node@1.12.5-next.1 + +## 1.8.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.1-next.0 + - @backstage/plugin-techdocs-node@1.12.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.2.0 + +## 1.8.11 + +### Patch Changes + +- 1a0e009: Fix cookie endpoint mock for `serve` +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/backend-common@0.22.0 + - @backstage/plugin-techdocs-node@1.12.4 + +## 1.8.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.22.0-next.1 + - @backstage/plugin-techdocs-node@1.12.4-next.1 + ## 1.8.10-next.0 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 4edb8f47a4..8db3eace5e 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "1.8.10-next.0", + "version": "1.8.12-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index d28d0cac49..6176df8d17 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/test-utils +## 1.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.6-next.0 + - @backstage/config@1.2.0 + - @backstage/core-app-api@1.12.5 + - @backstage/core-plugin-api@1.9.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.13 + - @backstage/plugin-permission-react@0.4.22 + +## 1.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.4 + - @backstage/core-app-api@1.12.5 + ## 1.5.5-next.0 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 2e46e3a9b0..136be68fe6 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.5.5-next.0", + "version": "1.5.6-next.0", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index 20703a1d9d..0cd38f9265 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/theme +## 0.5.6-next.0 + +### Patch Changes + +- 702fa7d: Internal refactor to fix an issue where the MUI 5 `v5-` class prefixing gets removed by tree shaking. + +## 0.5.4 + +### Patch Changes + +- f1462df: Fixed bug where scrollbars don't pick up the theme when in dark mode + ## 0.5.4-next.0 ### Patch Changes diff --git a/packages/theme/package.json b/packages/theme/package.json index 07eefe756f..8cdb23c1ec 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/theme", - "version": "0.5.4-next.0", + "version": "0.5.6-next.0", "description": "material-ui theme for use with Backstage.", "backstage": { "role": "web-library" diff --git a/packages/theme/src/unified/UnifiedThemeProvider.test.tsx b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx index da4af5abab..98fc73505d 100644 --- a/packages/theme/src/unified/UnifiedThemeProvider.test.tsx +++ b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx @@ -22,7 +22,6 @@ import { useTheme as useV5Theme } from '@mui/material/styles'; import { makeStyles as makeV5Styles } from '@mui/styles'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import './MuiClassNameSetup'; import { UnifiedThemeProvider } from './UnifiedThemeProvider'; import { themes } from './themes'; diff --git a/packages/theme/src/unified/UnifiedThemeProvider.tsx b/packages/theme/src/unified/UnifiedThemeProvider.tsx index 35abbe57d8..465a4dda24 100644 --- a/packages/theme/src/unified/UnifiedThemeProvider.tsx +++ b/packages/theme/src/unified/UnifiedThemeProvider.tsx @@ -15,7 +15,6 @@ */ import React, { ReactNode } from 'react'; -import './MuiClassNameSetup'; import { CssBaseline } from '@material-ui/core'; import { ThemeProvider, @@ -29,6 +28,7 @@ import { Theme as Mui5Theme, } from '@mui/material/styles'; import { UnifiedTheme } from './types'; +import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className'; /** * Props for {@link UnifiedThemeProvider}. @@ -41,10 +41,19 @@ export interface UnifiedThemeProviderProps { noCssBaseline?: boolean; } +/** + * This API is introduced in @mui/material (v5.0.5) as a replacement of deprecated createGenerateClassName & only affects v5 Material UI components from `@mui/*`. + * + * This call needs to be in the same module as the `UnifiedThemeProvider` to ensure that it doesn't get removed by tree shaking + */ +ClassNameGenerator.configure(componentName => { + return `v5-${componentName}`; +}); + // Background at https://mui.com/x/migration/migration-data-grid-v4/#using-mui-core-v4-with-v5 // Rather than disabling globals and custom seed, we instead only set a production prefix that -// won't collide with Material UI 5 styles. We've already got a separate class name generator for v5 set -// up in MuiClassNameSetup.ts, so only the production JSS needs deduplication. +// won't collide with Material UI 5 styles. We've already got the separate class name generator +// for v5 set up in just above, so only the production JSS needs deduplication. const generateV4ClassName = createGenerateClassName({ productionPrefix: 'jss4-', }); diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 370b221ea2..2d7acf4cd0 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-api-docs +## 0.11.6-next.0 + +### Patch Changes + +- 96cd13e: `DefaultApiExplorerPage` now accepts an optional `ownerPickerMode` for toggling the behavior of the `EntityOwnerPicker`, exposing a new mode `` particularly suitable for larger catalogs. In this new mode, `EntityOwnerPicker` will display all the users and groups present in the catalog. +- Updated dependencies + - @backstage/core-components@0.14.8-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.6-next.0 + - @backstage/core-plugin-api@1.9.2 + - @backstage/frontend-plugin-api@0.6.6-next.0 + - @backstage/plugin-catalog@1.20.1-next.0 + - @backstage/plugin-catalog-common@1.0.23 + - @backstage/plugin-catalog-react@1.12.1-next.0 + - @backstage/plugin-permission-react@0.4.22 + +## 0.11.5 + +### Patch Changes + +- 5d99272: Update local development dependencies. +- 725ff0b: Fix dark mode text color inside tables in `description:` from OpenAPI definitions +- Updated dependencies + - @backstage/plugin-catalog@1.20.0 + - @backstage/core-compat-api@0.2.5 + - @backstage/core-components@0.14.7 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-react@1.12.0 + - @backstage/frontend-plugin-api@0.6.5 + - @backstage/plugin-catalog-common@1.0.23 + +## 0.11.5-next.2 + +### Patch Changes + +- 725ff0b: Fix dark mode text color inside tables in `description:` from OpenAPI definitions +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.0-next.2 + - @backstage/plugin-catalog@1.20.0-next.2 + - @backstage/core-components@0.14.7-next.2 + - @backstage/core-compat-api@0.2.5-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + +## 0.11.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.6-next.1 + - @backstage/plugin-catalog@1.19.1-next.1 + - @backstage/plugin-catalog-react@1.11.4-next.1 + - @backstage/frontend-plugin-api@0.6.5-next.1 + - @backstage/core-compat-api@0.2.5-next.1 + ## 0.11.5-next.0 ### Patch Changes @@ -1326,8 +1380,7 @@ ### Patch Changes - 8f7b1835df: Updated dependency `msw` to `^0.41.0`. -- 811ff4bcf4: Updated `swagger-ui-react` to 4.11.1 in order to address a [XSS - vulnerability](https://github.com/advisories/GHSA-hqq7-2q2v-82xq) in `@braintree/sanitize-url` +- 811ff4bcf4: Updated `swagger-ui-react` to 4.11.1 in order to address a [XSS vulnerability](https://github.com/advisories/GHSA-hqq7-2q2v-82xq) in `@braintree/sanitize-url` - Updated dependencies - @backstage/plugin-catalog@1.3.0 - @backstage/plugin-catalog-react@1.1.1 diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md index 7523198298..2fc852777b 100644 --- a/plugins/api-docs/api-report.md +++ b/plugins/api-docs/api-report.md @@ -9,6 +9,7 @@ import { ApiEntity } from '@backstage/catalog-model'; import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { CatalogTableRow } from '@backstage/plugin-catalog'; +import { EntityOwnerPickerProps } from '@backstage/plugin-catalog-react'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { InfoCardVariants } from '@backstage/core-components'; import { JSX as JSX_2 } from 'react'; @@ -105,6 +106,7 @@ export type DefaultApiExplorerPageProps = { initiallySelectedFilter?: UserListFilterKind; columns?: TableColumn[]; actions?: TableProps['actions']; + ownerPickerMode?: EntityOwnerPickerProps['mode']; }; // @public (undocumented) diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 5d0521f283..6ece06888c 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.11.5-next.0", + "version": "0.11.6-next.0", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin" diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx index dc83c2528d..6b5917c52d 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx @@ -35,6 +35,7 @@ import { UserListFilterKind, UserListPicker, CatalogFilterLayout, + EntityOwnerPickerProps, } from '@backstage/plugin-catalog-react'; import React from 'react'; import { registerComponentRouteRef } from '../../routes'; @@ -60,6 +61,7 @@ export type DefaultApiExplorerPageProps = { initiallySelectedFilter?: UserListFilterKind; columns?: TableColumn[]; actions?: TableProps['actions']; + ownerPickerMode?: EntityOwnerPickerProps['mode']; }; /** @@ -67,7 +69,12 @@ export type DefaultApiExplorerPageProps = { * @public */ export const DefaultApiExplorerPage = (props: DefaultApiExplorerPageProps) => { - const { initiallySelectedFilter = 'all', columns, actions } = props; + const { + initiallySelectedFilter = 'all', + columns, + actions, + ownerPickerMode, + } = props; const configApi = useApi(configApiRef); const generatedSubtitle = `${ @@ -101,7 +108,7 @@ export const DefaultApiExplorerPage = (props: DefaultApiExplorerPageProps) => {